Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
19.exceptions.mt.cpp
Go to the documentation of this file.
1
30#include <stdexcept> // for exceptions
31#include <string> // for string
32
33#include <cassert> // for assert
34#include <cstdio> // for printf()
35
36#include <rw_cmdopt.h>
37#include <rw_driver.h>
38#include <rw_alarm.h> // for rw_alarm()
39#include <rw_thread.h> // for rw_thread_pool()
40#include <rw_valcmp.h>
41
42
44#ifndef NTHREADS
45# ifndef _RWSTD_REENTRANT
46# define MAX_THREADS 0
47# define NTHREADS 0
48# else
49# define MAX_THREADS 32
50# define NTHREADS 4
51# endif // _RWSTD_REENTRANT
52#endif // NTHREADS
53
54
56/* extern */ int rw_opt_nloops = 256 * 1024;
57/* extern */ int rw_opt_nthreads = NTHREADS;
58
59
61volatile int alarm_expired;
62
63extern "C" {
64
65static void handle_alarm (int)
66{
67 alarm_expired = 1;
68}
69
70} // extern "C"
71
72
73// string to intialize exceptions from
74static const char what_buf [] = {
75 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
76 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
77 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
78 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
79 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
80 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
81 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
82 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
83 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
84 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
85 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
86 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
87 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
88 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
89 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
90 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
91 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
92 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
93 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
94 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
95 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
96 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
97 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
98 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
99 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
100 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
101 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
102 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
103 "0123456789ABCDEF"
104};
105
106
107enum {
120
121
122struct DerivedException: std::invalid_argument
123{
124 DerivedException (const char *str)
125 : std::invalid_argument (str) { }
126};
127
128
129static void
130throw_exception (unsigned which, const char *what)
131{
132 switch (which) {
133 case exception_tag: throw std::exception ();
134 case logic_error_tag: throw std::logic_error (what);
135 case domain_error_tag: throw std::domain_error (what);
136 case invalid_argument_tag: throw std::invalid_argument (what);
137 case length_error_tag: throw std::length_error (what);
138 case out_of_range_tag: throw std::out_of_range (what);
139 case runtime_error_tag: throw std::runtime_error (what);
140 case range_error_tag: throw std::range_error (what);
141 case overflow_error_tag: throw std::overflow_error (what);
142 case underflow_error_tag: throw std::underflow_error (what);
143 case Derived_tag: throw DerivedException (what);
144
145 default: _RWSTD_ASSERT (!"logic error: bad exception tag");
146 }
147}
148
149
151extern "C" void*
153{
154 const rw_thread_t* const tid = (rw_thread_t*)arg;
155
156 std::printf ("thread procedure %ld starting...\n", tid->threadno);
157
158 for (unsigned i = 0; i < unsigned (rw_opt_nloops); ++i) {
159
160 if (alarm_expired)
161 break;
162
163 const std::size_t what_len = std::size_t (i % 1024);
164
165 const char* const what = what_buf + sizeof what_buf - what_len - 1;
166
167 const unsigned thrown = i % 11;
168
169 unsigned caught = _RWSTD_UINT_MAX;
170
171 try {
172 // construct and throw an exception object of one
173 // of the predefined standard exception classes
174 // initialized with a distinct what string
175 throw_exception (thrown, what);
176 }
177 catch (DerivedException ex) {
178 // catch the exception object by value and verify
179 // that the pointer returned by what() compares
180 // equal to the string the thrown object was
181 // constructed with
183 assert (0 == rw_strncmp (ex.what (), what));
184 }
185 catch (std::domain_error ex) {
187 assert (0 == rw_strncmp (ex.what (), what));
188 }
189 catch (std::invalid_argument ex) {
191 assert (0 == rw_strncmp (ex.what (), what));
192 }
193 catch (std::length_error ex) {
195 assert (0 == rw_strncmp (ex.what (), what));
196 }
197 catch (std::out_of_range ex) {
199 assert (0 == rw_strncmp (ex.what (), what));
200 }
201 catch (std::range_error ex) {
203 assert (0 == rw_strncmp (ex.what (), what));
204 }
205 catch (std::overflow_error ex) {
207 assert (0 == rw_strncmp (ex.what (), what));
208 }
209 catch (std::underflow_error ex) {
211 assert (0 == rw_strncmp (ex.what (), what));
212 }
213 catch (std::logic_error ex) {
215 assert (0 == rw_strncmp (ex.what (), what));
216 }
217 catch (std::runtime_error ex) {
219 assert (0 == rw_strncmp (ex.what (), what));
220 }
221 catch (std::exception ex) {
223 rw_strncmp (ex.what (), what);
224 }
225
226 // verify that an object of the thrown type was caught
227 assert (caught == thrown);
228 }
229
230 return 0;
231}
232
233
235static void
236test_multi (unsigned i, unsigned nactive)
237{
238 const std::size_t what_len = (i + nactive) % sizeof what_buf;
239
240 const char* const what = what_buf + sizeof what_buf - what_len - 1;
241
242 const unsigned thrown = (i + nactive) % 10 + 1;
243
244 try {
245 // construct and throw an exception object of a distinct type
246 // with a distinct what string at each level of recursion
247 throw_exception (thrown, what);
248 }
249 catch (std::exception &ex) {
250
251 // recursively throw another exception while the caught
252 // exception object is still active
253 if (nactive)
254 test_multi (i, nactive - 1);
255
256 // verify that the caught object's what string matches
257 // the string the object was originally constructed with
258 assert (0 == rw_strncmp (ex.what (), what));
259 }
260}
261
262extern "C" void*
264{
265 const rw_thread_t* const tid = (rw_thread_t*)arg;
266
267 std::printf ("thread procedure %ld starting...\n", tid->threadno);
268
269 for (unsigned i = 0; i < unsigned (rw_opt_nloops); ++i) {
270
271 if (alarm_expired)
272 break;
273
274 // exercise up to 4 simultaneously active exceptions
275 test_multi (i, i % 4);
276 }
277
278 return 0;
279}
280
281
283static int
284run_test (int, char**)
285{
286 // get the current alarm (if any) set for the test
287 // on the command line without resetting it
288 const unsigned max_sec = rw_alarm (0, rw_sig_hold);
289
290 // compute a shorter timeout for each of the two subtests
291 const unsigned nsec = 3 < max_sec ? max_sec / 2 : 0;
292
293 rw_info (0, 0, 0,
294 "single active exception per thread"
295 "%{?}; timeout in %u seconds%{;}",
296 0 != max_sec, nsec ? nsec : max_sec);
297
298 // set a shorter alarm if possible
299 if (nsec) {
300 alarm_expired = 0;
301 rw_alarm (nsec, handle_alarm);
302 }
303
304 const std::size_t nthreads = std::size_t (rw_opt_nthreads);
305
306#if 0 < NTHREADS
307
308 rw_fatal (0 == rw_thread_pool (0, nthreads, 0, test_single_exception, 0),
309 0, __LINE__, "rw_thread_pool() failed");
310
311#else // if !(0 < NTHREADS)
312
313 rw_thread_t tid = rw_thread_t ();
314
316
317#endif // NTHREADS
318
319 rw_info (0, 0, 0,
320 "multiple active exceptions per thread"
321 "%{?}; timeout in %u seconds%{;}",
322 0 != max_sec, nsec ? nsec : max_sec);
323
324 // set another shorter alarm if possible
325 if (nsec) {
326 alarm_expired = 0;
327 rw_alarm (nsec, handle_alarm);
328 }
329
330#if 0 < NTHREADS
331
332 rw_fatal (0 == rw_thread_pool (0, nthreads, 0, test_multi_exceptions, 0),
333 0, __LINE__, "rw_thread_pool() failed");
334
335#else // if !(0 < NTHREADS)
336
338
339#endif // NTHREADS
340
341 // restore the original alarm to go off approximately
342 // when the original alar would have if it hadn't been
343 // replaced above
344 if (nsec)
345 rw_alarm (2 * nsec, rw_sig_restore);
346
347 return 0;
348}
349
350
352int main (int argc, char *argv[])
353{
354 return rw_test (argc, argv, __FILE__,
355 "lib.std.exceptions",
356 "thread safety", run_test,
357 "|-nloops#0 " // must be non-negative
358 "|-nthreads#0-*", // must be in [0, MAX_THREADS]
360 int (MAX_THREADS),
362}
#define i
Definition 17.names.cpp:126
#define which
Definition 17.names.cpp:575
volatile int alarm_expired
int rw_opt_nthreads
void * test_multi_exceptions(void *arg)
#define NTHREADS
#define MAX_THREADS
@ runtime_error_tag
@ invalid_argument_tag
@ out_of_range_tag
@ overflow_error_tag
@ range_error_tag
@ length_error_tag
@ underflow_error_tag
@ Derived_tag
@ exception_tag
@ logic_error_tag
@ domain_error_tag
void * test_single_exception(void *arg)
int rw_opt_nloops
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
#define main
int caught
#define assert(expr)
Definition _cassert.h:40
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
const char * str
Definition exec.cpp:170
Definition json.h:5363
_TEST_EXPORT rw_signal_handler_t *const rw_sig_hold
Definition alarm.cpp:53
_TEST_EXPORT unsigned rw_alarm(unsigned int, rw_signal_handler_t *=0)
Definition alarm.cpp:173
_TEST_EXPORT rw_signal_handler_t *const rw_sig_restore
Definition alarm.cpp:56
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_fatal(int expr, const char *filename, int line, const char *fmtspec,...)
Definition driver.cpp:1596
_TEST_EXPORT int rw_thread_pool(rw_thread_t *, _RWSTD_SIZE_T, rw_thread_attr_t *, rw_thread_proc *, void **, _RWSTD_SIZE_T=0)
_TEST_EXPORT int rw_strncmp(const char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX, int=CMP_NULTERM)
DerivedException(const char *str)
long threadno
Definition rw_thread.h:43
int arg
Definition locale.cpp:2806