Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
thread.cpp
Go to the documentation of this file.
1
29// expand _TEST_EXPORT macros
30#define _RWSTD_TEST_SRC
31
32#include <rw_thread.h>
33#include <rw_alarm.h> // for rw_alarm()
34
35#include <stddef.h> // for size_t
36#include <string.h> // for memset()
37
38#ifndef _WIN32
39# include <stdio.h> // for FILE, fscanf(), popen()
40# include <unistd.h> // for sysconf(), _SC_NPROCESSORS_{CONF,ONLN}
41#else
42# include <windows.h> // for GetSystemInfo()
43#endif // _WIN32
44
45#ifndef _RWSTD_NO_PURE_C_HEADERS
46
47extern "C" {
48FILE* popen (const char*, const char*);
49} // extern "C"
50
51#endif // _RWSTD_NO_PURE_C_HEADERS
52
53
55static long maxthreads;
56
57
59static volatile int
60_rw_timeout_expired = 0;
61
62
66{
67 return _rw_timeout_expired != 0;
68}
69
70
72extern "C" {
73
74static void
75_rw_timeout_handler (int)
76{
77 _rw_timeout_expired = 1;
78}
79
80} // extern "C"
81
82
85#if defined (_RWSTD_POSIX_THREADS)
86
87# ifdef _RWSTD_EDG_ECCP
88 // disable error #450-D: the type "long long" is nonstandard
89 // issued for uses of the type in Linux system headers (e.g.,
90 // pthreadtypes.h)
91# pragma diag_suppress 450
92# endif // vanilla EDG eccp demo
93
94# include <pthread.h>
95
98 rw_thread_attr_t*,
99 rw_thread_proc *thr_proc,
100 void *thr_arg)
101{
102#ifdef _RWSTD_OS_SUNOS
103
104 static int concurrency_set;
105
106 if (0 == concurrency_set) {
107 pthread_setconcurrency (4);
108 concurrency_set = 1;
109 }
110
111#endif // _RWSTD_OS_SUNOS
112
113
114 rw_thread_t tmpid;
115
116 if (0 == thr_id) {
117 thr_id = &tmpid;
118 }
119
120 pthread_t tid;
121
122 // set the thread number *before* creating the thread
123 // so that it's visible in thr_proc when it starts to
124 // run even before pthread_create returns
125 thr_id->threadno = maxthreads;
126
127 const int result = pthread_create (&tid, 0, thr_proc, thr_arg);
128
129 if (0 == result) {
130 thr_id->id = (long)tid;
131 thr_id->handle = 0;
132 ++maxthreads;
133 }
134
135 return result;
136}
137
138
139_TEST_EXPORT int
140rw_thread_join (rw_thread_t thr_id, void **parg)
141{
142 const int result = pthread_join ((pthread_t)thr_id.id, parg);
143
144 return result;
145}
146
147
149#elif defined (_RWSTD_SOLARIS_THREADS)
150# include <thread.h>
151
152_TEST_EXPORT int
154 rw_thread_attr_t*,
155 rw_thread_proc *thr_proc,
156 void *thr_arg)
157{
158 static int concurrency_set;
159
160 if (0 == concurrency_set) {
161 thr_setconcurrency (4);
162 concurrency_set = 1;
163 }
164
165 rw_thread_t tmpid;
166
167 if (0 == thr_id) {
168 thr_id = &tmpid;
169 }
170
171 thread_t tid;
172
173 // set the thread number *before* creating the thread
174 // so that it's visible in thr_proc when it starts to
175 // run even before thr_create returns
176 thr_id->threadno = maxthreads;
177
178 const int result =
179 thr_create (0, // stack_base
180 0, // stack_size
181 thr_proc, // start_func
182 thr_arg, // arg
183 0, // flags
184 &tid); // new_thread_ID
185
186 if (0 == result) {
187 thr_id->id = (long)tid;
188 thr_id->handle = 0;
189 ++maxthreads;
190 }
191
192 return result;
193}
194
195
196_TEST_EXPORT int
197rw_thread_join (rw_thread_t thr_id, void **parg)
198{
199 const int result = thr_join ((thread_t)thr_id.id, 0, parg);
200
201 return result;
202}
203
204
206#elif defined (_RWSTD_DEC_THREADS)
207
208# include <setjmp.h>
209# include <cma.h>
210
211_TEST_EXPORT int
213 rw_thread_attr_t*,
214 rw_thread_proc *thr_proc,
215 void *thr_arg)
216{
217 rw_thread_t tmpid;
218
219 if (0 == thr_id) {
220 thr_id = &tmpid;
221 }
222
223 int result = 0;
224
225 cma_t_thread tid;
226
227 // set the thread number *before* creating the thread
228 // so that it's visible in thr_proc when it starts to
229 // run even before cma_thread_create returns
230 thr_id->threadno = maxthreads;
231
232 TRY {
233 // cma_thread_create() returns void but throws an exception on error
234 cma_thread_create (&tid, // new_thread
235 0, // attr
236 thr_proc, // start_routine
237 &thr_arg); // arg
238
239 thr_id->id = tid.field1;
240 thr_id->handle = (void*)tid.field2;
241 ++maxthreads;
242 }
243 CATCH_ALL {
244 result = -1;
245 }
246 ENDTRY
247
248 return result;
249}
250
251
252_TEST_EXPORT int
253rw_thread_join (rw_thread_t thr_id, void **parg)
254{
255 int status = 0;
256
257 cma_t_thread tid = {
258 thr_id.id, (long)thr_id.handle
259 };
260
261 TRY {
262 // cma_thread_join() returns void but throws an exception on error
263 cma_thread_join (&tid, 0, parg);
264 }
265 CATCH_ALL {
266 status = -1;
267 }
268 ENDTRY
269
270 return status;
271}
272
273
275#elif defined (_WIN32) && defined (_MT)
276# ifdef __MINGW32__
277# include <stdint.h> // for uintptr_t
278# endif
279# include <process.h> // for _beginthreadex()
280
281_TEST_EXPORT int
283 rw_thread_attr_t*,
284 rw_thread_proc *thr_proc,
285 void *thr_arg)
286{
287 int result = 0;
288
289 rw_thread_t tmpid;
290
291 if (0 == thr_id)
292 thr_id = &tmpid;
293
294 unsigned nid; // numerical id
295
296 typedef unsigned int (__stdcall *win32_thr_proc_t)(void *);
297 win32_thr_proc_t win32_thr_proc =
298 _RWSTD_REINTERPRET_CAST (win32_thr_proc_t, thr_proc);
299
300 // set the thread number *before* creating the thread
301 // so that it's visible in thr_proc when it starts to
302 // run even before CreateThread returns
303 thr_id->threadno = maxthreads;
304
305 const uintptr_t hthread =
306 _beginthreadex (0, // lpThreadAttributes
307 0, // dwStackSize
308 win32_thr_proc, // lpStartAddress
309 thr_arg, // lpParameter
310 0, // dwCreationFlags
311 &nid); // lpThreadId
312
313 if (!hthread) {
314 thr_id->id = -1;
315 thr_id->handle = 0;
316 result = -1;
317 }
318 else {
319 thr_id->id = nid;
320 thr_id->handle = _RWSTD_REINTERPRET_CAST (void*, hthread);
321 ++maxthreads;
322 }
323
324 return result;
325}
326
327
328_TEST_EXPORT int
329rw_thread_join (rw_thread_t thr_id, void **parg)
330{
331 int result = 0;
332
333 const DWORD retcode = WaitForSingleObject (thr_id.handle, INFINITE);
334
335 if (WAIT_OBJECT_0 == retcode) {
336 if (parg) {
337 DWORD exit_code;
338
339 if (GetExitCodeThread (thr_id.handle, &exit_code))
340 *parg = (void*)exit_code;
341 else
342 result = -1;
343 }
344 }
345 else {
346 result = -1;
347 }
348
349 return result;
350}
351
352
354#else // unknown/missing threads environment
355
356# include <errno.h>
357
358# ifndef ENOTSUP
359# if defined (_RWSTD_OS_AIX)
360# define ENOTSUP 124
361# elif defined (_RWSTD_OS_HP_UX)
362# define ENOTSUP 252
363# elif defined (_RWSTD_OS_IRIX64)
364# define ENOTSUP 1008
365# elif defined (_RWSTD_OS_LINUX)
366# define ENOTSUP 524
367# elif defined (_RWSTD_OS_OSF1)
368# define ENOTSUP 99
369# elif defined (_RWSTD_OS_SUNOS)
370# define ENOTSUP 48
371# elif defined (_WIN32)
372# define ENOTSUP ENOSYS
373# else
374# define ENOTSUP 9999
375# endif
376# endif // ENOTSUP
377
378_TEST_EXPORT int
380 rw_thread_attr_t*,
382 void*)
383{
384 _RWSTD_UNUSED (maxthreads);
385
386 return ENOTSUP;
387}
388
389
390_TEST_EXPORT int
392{
393 return ENOTSUP;
394}
395
396#endif // threads environment
397
398
400// retrieves the number of processors/cores on the system
401_TEST_EXPORT int
403{
404#ifndef _WIN32
405
406 const char* const cmd = {
407 // shell command(s) to obtain the number of processors
408
409# ifdef _RWSTD_OS_AIX
410 // AIX: /etc/lsdev -Cc processor | wc -l
411 "/etc/lsdev -Cc processor | /usr/bin/wc -l"
412# elif defined (_RWSTD_OS_LINUX)
413 // Linux: cat /proc/cpuinfo | grep processor | wc -l
414 "cat /proc/cpuinfo "
415 " | grep processor "
416 " | wc -l"
417# elif defined (_RWSTD_OS_FREEBSD)
418 // FreeBSD: /sbin/sysctl -n hw.ncpu
419 "/sbin/sysctl -n hw.ncpu"
420# elif defined (_RWSTD_OS_HP_UX)
421 // HP-UX: /etc/ioscan -k -C processor | grep processor | wc -l
422 "/etc/ioscan -k -C processor "
423 " | /usr/bin/grep processor "
424 " | /usr/bin/wc -l"
425# elif defined (_RWSTD_OS_IRIX64)
426 // IRIX: hinv | /usr/bin/grep "^[1-9][0-9]* .* Processor"
427 "/sbin/hinv "
428 " | /usr/bin/grep \"^[1-9][0-9]* .* Processor\""
429# elif defined (_RWSTD_OS_OSF1)
430 // Tru64 UNIX: /usr/sbin/psrinfo | grep online | wc -l
431 "/usr/sbin/psrinfo "
432 " | /usr/bin/grep on[-]*line "
433 " | /usr/bin wc -l"
434# elif defined (_RWSTD_OS_SUNOS)
435 // Solaris: /usr/bin/mpstat | wc -l
436 "/usr/bin/mpstat "
437 " | /usr/bin/grep -v \"^CPU\" "
438 " | /usr/bin/wc -l"
439# else
440 0
441# endif
442
443 };
444
445 int ncpus = -1;
446
447# ifdef _SC_NPROCESSORS_ONLN
448 // try to obtain the number of processors that are currently online
449 // programmatically and fall back on the shell script above if it
450 // fails
451 ncpus = int (sysconf (_SC_NPROCESSORS_ONLN));
452
453# elif defined (_SC_NPROCESSORS_CONF)
454
455 // try to obtain the number of processors the system is configured
456 // with (not all of them are necessarily online) programmatically
457 // and fall back on the shell script above if it fails
458 ncpus = int (sysconf (_SC_NPROCESSORS_CONF));
459
460# endif // _SC_NPROCESSORS_CONF
461
462 if (ncpus < 1 && cmd) {
463 // if the number of processors couldn't be determined using
464 // sysconf() above, open and read the output of the command
465 // from a pipe
466 FILE* const fp = popen (cmd, "r");
467
468 if (fp) {
469 int tmp = 0;
470
471 int n = fscanf (fp, "%d", &tmp);
472
473 if (1 == n)
474 ncpus = tmp;
475
476 fclose (fp);
477 }
478 }
479
480 return ncpus;
481
482#else // _WIN32
483
484 SYSTEM_INFO info;
485 GetSystemInfo (&info);
486 return int (info.dwNumberOfProcessors);
487
488#endif // _WIN32
489}
490
491
493_TEST_EXPORT int
495 size_t nthrs,
496 rw_thread_attr_t*,
497 rw_thread_proc *thr_proc,
498 void* *thr_arg,
499 size_t timeout)
500{
501 // apply timeout if one was specified
502 if (0 != timeout) {
503 _rw_timeout_expired = 0;
504 rw_alarm (unsigned (timeout), _rw_timeout_handler);
505 }
506
507 // small buffer for thread ids when invoked with (thr_id == 0)
508 rw_thread_t id_buf [16];
509
510 const bool join = 0 == thr_id;
511
512#ifdef _RWSTD_REENTRANT
513
514 if (_RWSTD_SIZE_MAX == nthrs) {
515 // when the number of threads is -1 use the number
516 // of processors plus 1 (in case it's 1 to begin
517 // with)
518
519 const int ncpus = rw_get_cpus ();
520
521 if (0 < ncpus)
522 nthrs = size_t (ncpus) + 1;
523 else
524 nthrs = 2;
525 }
526
527#else
528
529 // when not reentrant/thread safe emulate the creation
530 // of a single thread and then waiting for it to finish
531 // by simply calling the thread procedure
532
533 if (1 == nthrs && join) {
534
535 if (0 == thr_id) {
536 thr_id = id_buf;
537 memset (thr_id, 0, sizeof *thr_id);
538 }
539
540 // when the thr_arg pointer is 0 pass the address
541 // of each thread's id as the argument to thr_proc
542 void* const arg = thr_arg ? thr_arg [0] : (void*)(thr_id);
543
544 void* const thr_result = thr_proc (arg);
545
546 if (thr_arg)
547 thr_arg [0] = thr_result;
548
549 return 0;
550 }
551#endif // !_RWSTD_REENTRANT
552
553 bool delete_ids = false;
554
555 if (0 == thr_id) {
556 // save thread idsso that they (and no other threads)
557 // can be joined later
558 if (sizeof id_buf / sizeof *id_buf < nthrs) {
559 delete_ids = true;
560 thr_id = new rw_thread_t [nthrs];
561 }
562 else
563 thr_id = id_buf;
564 }
565
566 // create a pool of threads storing their id's
567 // in consecutive elements of the thr_id array
568 for (size_t i = 0; i != nthrs; ++i) {
569
570 // when the thr_arg pointer is 0 pass the address
571 // of each thread's id as the argument to thr_proc
572 void* const next_arg = thr_arg ? thr_arg [i] : (void*)(thr_id + i);
573
574 if (rw_thread_create (thr_id + i, 0, thr_proc, next_arg)) {
575 if (delete_ids)
576 delete[] thr_id;
577
578 return int (i + 1);
579 }
580 }
581
582 // invoking the function with a 0 thr_id pointer
583 // is a request to join all threads in the pool
584 if (join) {
585 for (size_t i = 0; i != nthrs; ++i) {
586
587 // avoid advancing through the thr_arg array
588 // when it's 0 (and have rw_thread_join() simply
589 // ignore the thread's return value)
590 void** next_arg = thr_arg ? thr_arg + i : 0;
591
592 rw_thread_join (thr_id [i], next_arg);
593 }
594
595 if (delete_ids)
596 delete[] thr_id;
597 }
598
599 return 0;
600}
#define i
Definition 17.names.cpp:126
#define tmp
Definition 17.names.cpp:553
#define n
Definition 17.names.cpp:130
volatile int result
#define TRY
#define FILE
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
_TEST_EXPORT unsigned rw_alarm(unsigned int, rw_signal_handler_t *=0)
Definition alarm.cpp:173
#define _TEST_EXPORT
Definition rw_testdefs.h:55
void * rw_thread_proc(void *)
Definition rw_thread.h:36
long threadno
Definition rw_thread.h:43
void * handle
Definition rw_thread.h:45
_TEST_EXPORT int rw_thread_pool(rw_thread_t *thr_id, size_t nthrs, rw_thread_attr_t *, rw_thread_proc *thr_proc, void **thr_arg, size_t timeout)
Definition thread.cpp:494
_TEST_EXPORT int rw_thread_create(rw_thread_t *, rw_thread_attr_t *, rw_thread_proc *, void *)
Definition thread.cpp:379
#define ENOTSUP
Definition thread.cpp:374
_TEST_EXPORT int rw_thread_join(rw_thread_t, void **)
Definition thread.cpp:391
_TEST_EXPORT int rw_get_cpus()
Definition thread.cpp:402
_TEST_EXPORT int rw_thread_pool_timeout_expired()
Definition thread.cpp:65
FILE * popen(const char *, const char *)
int arg
Definition locale.cpp:2806