4
* Copyright Ericsson AB 2004-2009. All Rights Reserved.
6
* The contents of this file are subject to the Erlang Public License,
7
* Version 1.1, (the "License"); you may not use this file except in
8
* compliance with the License. You should have received a copy of the
9
* Erlang Public License along with this software. If not, it can be
10
* retrieved online at http://www.erlang.org/.
12
* Software distributed under the License is distributed on an "AS IS"
13
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
* the License for the specific language governing rights and limitations
21
* Description: A Thread library for use in the ERTS and other OTP
23
* Author: Rickard Green
30
#undef ETHR_STACK_GUARD_SIZE
32
#if defined(ETHR_PTHREADS)
34
#ifdef ETHR_TIME_WITH_SYS_TIME
36
# include <sys/time.h>
38
# ifdef ETHR_HAVE_SYS_TIME_H
39
# include <sys/time.h>
44
#include <sys/types.h>
48
#ifdef ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE
49
# define ETHR_STACK_GUARD_SIZE (pagesize)
52
#elif defined(ETHR_WIN32_THREADS)
54
#undef WIN32_LEAN_AND_MEAN
55
#define WIN32_LEAN_AND_MEAN
61
#error "Missing thread implementation"
66
#define ETHR_FORCE_INLINE_FUNCS
67
#define ETHR_INLINE_FUNC_NAME_(X) X ## __
70
#ifndef ETHR_HAVE_ETHREAD_DEFINES
71
#error Missing configure defines
75
* ----------------------------------------------------------------------------
77
* ----------------------------------------------------------------------------
80
#define ETHR_MAX_THREADS 2048 /* Has to be an even power of 2 */
82
static int ethr_not_inited = 1;
84
#define ASSERT(A) ETHR_ASSERT((A))
86
static void *(*allocp)(size_t) = malloc;
87
static void *(*reallocp)(void *, size_t) = realloc;
88
static void (*freep)(void *) = free;
90
#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
91
ethr_atomic_protection_t ethr_atomic_protection__[1 << ETHR_ATOMIC_ADDR_BITS];
94
void *(*thread_create_prepare_func)(void) = NULL;
95
void (*thread_create_parent_func)(void *) = NULL;
96
void (*thread_create_child_func)(void *) = NULL;
98
typedef struct ethr_xhndl_list_ ethr_xhndl_list;
99
struct ethr_xhndl_list_ {
100
ethr_xhndl_list *next;
104
static size_t pagesize;
105
#define ETHR_PAGE_ALIGN(SZ) (((((size_t) (SZ)) - 1)/pagesize + 1)*pagesize)
106
static size_t min_stack_size; /* kilo words */
107
static size_t max_stack_size; /* kilo words */
108
#define ETHR_B2KW(B) ((((size_t) (B)) - 1)/(sizeof(void *)*1024) + 1)
109
#define ETHR_KW2B(KW) (((size_t) (KW))*sizeof(void *)*1024)
111
ethr_mutex xhndl_mtx;
112
ethr_xhndl_list *xhndl_list;
115
init_common(ethr_init_data *id)
120
reallocp = id->realloc;
122
thread_create_prepare_func = id->thread_create_prepare_func;
123
thread_create_parent_func = id->thread_create_parent_func;
124
thread_create_child_func = id->thread_create_child_func;
126
if (!allocp || !reallocp || !freep)
130
pagesize = (size_t) sysconf(_SC_PAGESIZE);
131
#elif defined(HAVE_GETPAGESIZE)
132
pagesize = (size_t) getpagesize();
134
pagesize = (size_t) 4*1024; /* Guess 4 KB */
137
/* User needs at least 4 KB */
138
min_stack_size = 4*1024;
139
#if SIZEOF_VOID_P == 8
140
/* Double that on 64-bit archs */
143
/* On some systems as much as about 4 KB is used by the system */
144
min_stack_size += 4*1024;
145
/* There should be room for signal handlers */
147
min_stack_size += SIGSTKSZ;
149
min_stack_size += pagesize;
151
/* The system may think that we need more stack */
152
#if defined(PTHREAD_STACK_MIN)
153
if (min_stack_size < PTHREAD_STACK_MIN)
154
min_stack_size = PTHREAD_STACK_MIN;
155
#elif defined(_SC_THREAD_STACK_MIN)
157
size_t thr_min_stk_sz = (size_t) sysconf(_SC_THREAD_STACK_MIN);
158
if (min_stack_size < thr_min_stk_sz)
159
min_stack_size = thr_min_stk_sz;
162
/* The guard is at least on some platforms included in the stack size
163
passed when creating threads */
164
#ifdef ETHR_STACK_GUARD_SIZE
165
min_stack_size += ETHR_STACK_GUARD_SIZE;
167
min_stack_size = ETHR_PAGE_ALIGN(min_stack_size);
169
min_stack_size = ETHR_B2KW(min_stack_size);
171
max_stack_size = 32*1024*1024;
172
#if SIZEOF_VOID_P == 8
175
max_stack_size = ETHR_B2KW(max_stack_size);
179
res = ethr_mutex_init(&xhndl_mtx);
183
res = ethr_mutex_set_forksafe(&xhndl_mtx);
184
if (res != 0 && res != ENOTSUP)
191
ethr_install_exit_handler(void (*funcp)(void))
193
ethr_xhndl_list *xhp;
197
if (ethr_not_inited) {
206
xhp = (ethr_xhndl_list *) (*allocp)(sizeof(ethr_xhndl_list));
210
res = ethr_mutex_lock__(&xhndl_mtx);
212
(*freep)((void *) xhp);
217
xhp->next = xhndl_list;
220
res = ethr_mutex_unlock__(&xhndl_mtx);
228
run_exit_handlers(void)
231
ethr_xhndl_list *xhp;
233
res = ethr_mutex_lock__(&xhndl_mtx);
239
res = ethr_mutex_unlock__(&xhndl_mtx);
243
for (; xhp; xhp = xhp->next)
247
#if defined(ETHR_PTHREADS)
248
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
249
* pthread implementation *
256
void *(*thr_func)(void *);
261
static int no_ethreads;
262
static ethr_mutex no_ethrs_mtx;
264
#ifndef ETHR_HAVE_PTHREAD_ATFORK
265
#define ETHR_HAVE_PTHREAD_ATFORK 0
268
#if !ETHR_HAVE_PTHREAD_ATFORK
269
#warning "Cannot enforce fork-safety"
273
* ----------------------------------------------------------------------------
275
* ----------------------------------------------------------------------------
279
* Functions with safe_ prefix aborts on failure. To be used when
280
* we cannot recover after failure.
283
static ETHR_INLINE void
284
safe_mutex_lock(pthread_mutex_t *mtxp)
286
int res = pthread_mutex_lock(mtxp);
291
static ETHR_INLINE void
292
safe_mutex_unlock(pthread_mutex_t *mtxp)
294
int res = pthread_mutex_unlock(mtxp);
299
static ETHR_INLINE void
300
safe_cond_signal(pthread_cond_t *cndp)
302
int res = pthread_cond_signal(cndp);
307
#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
309
static volatile int rec_mtx_attr_need_init = 1;
310
static pthread_mutexattr_t rec_mtx_attr;
312
static int init_rec_mtx_attr(void);
316
#if ETHR_HAVE_PTHREAD_ATFORK
318
static ethr_mutex forksafe_mtx = ETHR_MUTEX_INITER;
320
static void lock_mutexes(void)
322
ethr_mutex *m = &forksafe_mtx;
325
safe_mutex_lock(&m->pt_mtx);
329
} while (m != &forksafe_mtx);
332
static void unlock_mutexes(void)
334
ethr_mutex *m = forksafe_mtx.prev;
337
safe_mutex_unlock(&m->pt_mtx);
341
} while (m->next != &forksafe_mtx);
344
#if ETHR_INIT_MUTEX_IN_CHILD_AT_FORK
346
static void reinit_mutexes(void)
348
ethr_mutex *m = forksafe_mtx.prev;
350
pthread_mutexattr_t *attrp = NULL;
352
#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
354
if (rec_mtx_attr_need_init) {
355
int res = init_rec_mtx_attr();
359
attrp = &rec_mtx_attr;
362
if (pthread_mutex_init(&m->pt_mtx, attrp) != 0)
367
} while (m->next != &forksafe_mtx);
375
static int init_done = 0;
381
forksafe_mtx.prev = &forksafe_mtx;
382
forksafe_mtx.next = &forksafe_mtx;
384
res = pthread_atfork(lock_mutexes,
386
#if ETHR_INIT_MUTEX_IN_CHILD_AT_FORK
400
#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
402
#if defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETTYPE)
404
#define SET_REC_MUTEX_ATTR(AP) \
405
pthread_mutexattr_settype((AP), PTHREAD_MUTEX_RECURSIVE);
407
#elif defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
409
#define SET_REC_MUTEX_ATTR(AP) \
410
pthread_mutexattr_setkind_np((AP), PTHREAD_MUTEX_RECURSIVE_NP);
414
#error "Don't know how to set recursive mutex attributes"
419
init_rec_mtx_attr(void)
422
static pthread_mutex_t attrinit_mtx = PTHREAD_MUTEX_INITIALIZER;
424
mres = pthread_mutex_lock(&attrinit_mtx);
427
/* Got here under race conditions; check again ... */
428
if (!rec_mtx_attr_need_init)
431
res = pthread_mutexattr_init(&rec_mtx_attr);
433
res = SET_REC_MUTEX_ATTR(&rec_mtx_attr);
435
rec_mtx_attr_need_init = 0;
437
(void) pthread_mutexattr_destroy(&rec_mtx_attr);
441
mres = pthread_mutex_unlock(&attrinit_mtx);
447
#endif /* #if ETHR_HAVE_ETHR_REC_MUTEX_INIT */
449
static ETHR_INLINE void thr_exit_cleanup(void)
452
safe_mutex_lock(&no_ethrs_mtx.pt_mtx);
453
ASSERT(no_ethreads > 0);
455
safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
458
static void *thr_wrapper(void *vtwd)
461
thr_wrap_data_ *twd = (thr_wrap_data_ *) vtwd;
462
void *(*thr_func)(void *) = twd->thr_func;
463
void *arg = twd->arg;
465
safe_mutex_lock(&twd->mtx);
467
if (thread_create_child_func)
468
(*thread_create_child_func)(twd->prep_func_res);
470
twd->initialized = 1;
472
safe_cond_signal(&twd->cnd);
473
safe_mutex_unlock(&twd->mtx);
475
res = (*thr_func)(arg);
482
* ----------------------------------------------------------------------------
484
* ----------------------------------------------------------------------------
488
ethr_init(ethr_init_data *id)
492
if (!ethr_not_inited)
497
res = init_common(id);
501
#if ETHR_HAVE_PTHREAD_ATFORK
506
res = ethr_mutex_init(&no_ethrs_mtx);
509
res = ethr_mutex_set_forksafe(&no_ethrs_mtx);
510
if (res != 0 && res != ENOTSUP)
513
#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
516
for (i = 0; i < (1 << ETHR_ATOMIC_ADDR_BITS); i++) {
517
#ifdef ETHR_HAVE_PTHREAD_SPIN_LOCK
518
res = pthread_spin_init(ðr_atomic_protection__[i].u.spnlck, 0);
520
res = ethr_mutex_init(ðr_atomic_protection__[i].u.mtx);
537
ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg,
543
int use_stack_size = (opts && opts->suggested_stack_size >= 0
544
? opts->suggested_stack_size
545
: -1 /* Use system default */);
547
#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
548
if (use_stack_size < 0)
549
use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
557
if (ethr_not_inited) {
567
/* Call prepare func if it exist */
568
if (thread_create_prepare_func)
569
twd.prep_func_res = (*thread_create_prepare_func)();
571
twd.prep_func_res = NULL;
573
/* Set som thread attributes */
574
res = pthread_attr_init(&attr);
576
goto cleanup_parent_func;
577
res = pthread_mutex_init(&twd.mtx, NULL);
579
goto cleanup_attr_destroy;
580
res = pthread_cond_init(&twd.cnd, NULL);
582
goto cleanup_mutex_destroy;
584
/* Schedule child thread in system scope (if possible) ... */
585
res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
586
if (res != 0 && res != ENOTSUP)
587
goto cleanup_cond_destroy;
589
if (use_stack_size >= 0) {
590
size_t suggested_stack_size = (size_t) use_stack_size;
593
suggested_stack_size /= 2; /* Make sure we got margin */
595
#ifdef ETHR_STACK_GUARD_SIZE
596
/* The guard is at least on some platforms included in the stack size
597
passed when creating threads */
598
suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE);
600
if (suggested_stack_size < min_stack_size)
601
stack_size = ETHR_KW2B(min_stack_size);
602
else if (suggested_stack_size > max_stack_size)
603
stack_size = ETHR_KW2B(max_stack_size);
605
stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
606
(void) pthread_attr_setstacksize(&attr, stack_size);
609
#ifdef ETHR_STACK_GUARD_SIZE
610
(void) pthread_attr_setguardsize(&attr, ETHR_STACK_GUARD_SIZE);
613
/* Detached or joinable... */
614
res = pthread_attr_setdetachstate(&attr,
615
(opts && opts->detached
616
? PTHREAD_CREATE_DETACHED
617
: PTHREAD_CREATE_JOINABLE));
619
goto cleanup_cond_destroy;
621
res = pthread_mutex_lock(&twd.mtx);
624
goto cleanup_cond_destroy;
626
safe_mutex_lock(&no_ethrs_mtx.pt_mtx);
627
if (no_ethreads < ETHR_MAX_THREADS) {
629
safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
633
safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
634
goto cleanup_mutex_unlock;
637
res = pthread_create((pthread_t *) tid, &attr, thr_wrapper, (void *) &twd);
640
safe_mutex_lock(&no_ethrs_mtx.pt_mtx);
641
ASSERT(no_ethreads > 0);
643
safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
647
/* Wait for child to initialize... */
648
while (!twd.initialized) {
649
res = pthread_cond_wait(&twd.cnd, &twd.mtx);
650
if (res != 0 && res != EINTR)
657
cleanup_mutex_unlock:
658
dres = pthread_mutex_unlock(&twd.mtx);
661
cleanup_cond_destroy:
662
dres = pthread_cond_destroy(&twd.cnd);
665
cleanup_mutex_destroy:
666
dres = pthread_mutex_destroy(&twd.mtx);
669
cleanup_attr_destroy:
670
dres = pthread_attr_destroy(&attr);
674
if (thread_create_parent_func)
675
(*thread_create_parent_func)(twd.prep_func_res);
681
ethr_thr_join(ethr_tid tid, void **res)
684
if (ethr_not_inited) {
689
return pthread_join((pthread_t) tid, res);
693
ethr_thr_detach(ethr_tid tid)
696
if (ethr_not_inited) {
701
return pthread_detach((pthread_t) tid);
705
ethr_thr_exit(void *res)
708
if (ethr_not_inited) {
720
return (ethr_tid) pthread_self();
724
ethr_equal_tids(ethr_tid tid1, ethr_tid tid2)
726
return pthread_equal((pthread_t) tid1, (pthread_t) tid2);
736
ethr_mutex_init(ethr_mutex *mtx)
739
if (ethr_not_inited) {
747
mtx->initialized = ETHR_MUTEX_INITIALIZED;
752
return pthread_mutex_init(&mtx->pt_mtx, NULL);
755
#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
758
ethr_rec_mutex_init(ethr_mutex *mtx)
761
if (ethr_not_inited) {
769
mtx->initialized = ETHR_MUTEX_INITIALIZED;
771
if (rec_mtx_attr_need_init)
777
return pthread_mutex_init(&mtx->pt_mtx, &rec_mtx_attr);
780
#endif /* #if ETHR_HAVE_ETHR_REC_MUTEX_INIT */
783
ethr_mutex_destroy(ethr_mutex *mtx)
786
if (ethr_not_inited) {
790
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
797
ethr_mutex_unset_forksafe(mtx);
800
mtx->initialized = 0;
802
return pthread_mutex_destroy(&mtx->pt_mtx);
805
int ethr_mutex_set_forksafe(ethr_mutex *mtx)
809
if (ethr_not_inited) {
813
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
818
#if ETHR_HAVE_PTHREAD_ATFORK
819
res = pthread_mutex_lock(&forksafe_mtx.pt_mtx);
822
if (!forksafe_mtx.next) {
823
ASSERT(!forksafe_mtx.prev);
827
/* forksafe already set for this mutex */
831
mtx->next = forksafe_mtx.next;
832
mtx->prev = &forksafe_mtx;
833
forksafe_mtx.next->prev = mtx;
834
forksafe_mtx.next = mtx;
837
res = pthread_mutex_unlock(&forksafe_mtx.pt_mtx);
839
#else /* #if ETHR_HAVE_PTHREAD_ATFORK */
841
#endif /* #if ETHR_HAVE_PTHREAD_ATFORK */
845
int ethr_mutex_unset_forksafe(ethr_mutex *mtx)
849
if (ethr_not_inited) {
853
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
858
#if ETHR_HAVE_PTHREAD_ATFORK
859
res = pthread_mutex_lock(&forksafe_mtx.pt_mtx);
862
if (!forksafe_mtx.next) {
863
ASSERT(!forksafe_mtx.prev);
867
/* forksafe already unset for this mutex */
871
mtx->prev->next = mtx->next;
872
mtx->next->prev = mtx->prev;
876
res = pthread_mutex_unlock(&forksafe_mtx.pt_mtx);
878
#else /* #if ETHR_HAVE_PTHREAD_ATFORK */
880
#endif /* #if ETHR_HAVE_PTHREAD_ATFORK */
885
ethr_mutex_trylock(ethr_mutex *mtx)
888
if (ethr_not_inited) {
892
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
897
return ethr_mutex_trylock__(mtx);
901
ethr_mutex_lock(ethr_mutex *mtx)
904
if (ethr_not_inited) {
908
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
913
return ethr_mutex_lock__(mtx);
917
ethr_mutex_unlock(ethr_mutex *mtx)
920
if (ethr_not_inited) {
924
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
929
return ethr_mutex_unlock__(mtx);
933
* Condition variable functions
937
ethr_cond_init(ethr_cond *cnd)
940
if (ethr_not_inited) {
948
cnd->initialized = ETHR_COND_INITIALIZED;
950
return pthread_cond_init(&cnd->pt_cnd, NULL);
954
ethr_cond_destroy(ethr_cond *cnd)
957
if (ethr_not_inited) {
961
if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
965
cnd->initialized = 0;
967
return pthread_cond_destroy(&cnd->pt_cnd);
971
ethr_cond_signal(ethr_cond *cnd)
974
if (ethr_not_inited) {
978
if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
983
return pthread_cond_signal(&cnd->pt_cnd);
987
ethr_cond_broadcast(ethr_cond *cnd)
990
if (ethr_not_inited) {
994
if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
999
return pthread_cond_broadcast(&cnd->pt_cnd);
1003
ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
1006
if (ethr_not_inited) {
1011
|| cnd->initialized != ETHR_COND_INITIALIZED
1013
|| mtx->initialized != ETHR_MUTEX_INITIALIZED) {
1018
return pthread_cond_wait(&cnd->pt_cnd, &mtx->pt_mtx);
1022
ethr_cond_timedwait(ethr_cond *cnd, ethr_mutex *mtx, ethr_timeval *timeout)
1026
if (ethr_not_inited) {
1031
|| cnd->initialized != ETHR_COND_INITIALIZED
1033
|| mtx->initialized != ETHR_MUTEX_INITIALIZED
1040
to.tv_sec = timeout->tv_sec;
1041
to.tv_nsec = timeout->tv_nsec;
1043
return pthread_cond_timedwait(&cnd->pt_cnd, &mtx->pt_mtx, &to);
1047
#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
1050
ethr_rwmutex_init(ethr_rwmutex *rwmtx)
1053
if (ethr_not_inited) {
1061
rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
1063
return pthread_rwlock_init(&rwmtx->pt_rwlock, NULL);
1067
ethr_rwmutex_destroy(ethr_rwmutex *rwmtx)
1071
if (ethr_not_inited) {
1075
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1080
res = pthread_rwlock_destroy(&rwmtx->pt_rwlock);
1082
rwmtx->initialized = 0;
1088
ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
1091
if (ethr_not_inited) {
1095
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1100
return ethr_rwmutex_tryrlock__(rwmtx);
1104
ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
1107
if (ethr_not_inited) {
1111
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1116
return ethr_rwmutex_rlock__(rwmtx);
1120
ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
1123
if (ethr_not_inited) {
1127
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1132
return ethr_rwmutex_runlock__(rwmtx);
1136
ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
1139
if (ethr_not_inited) {
1143
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1148
return ethr_rwmutex_tryrwlock__(rwmtx);
1152
ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
1155
if (ethr_not_inited) {
1159
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1164
return ethr_rwmutex_rwlock__(rwmtx);
1168
ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
1171
if (ethr_not_inited) {
1175
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
1180
return ethr_rwmutex_rwunlock__(rwmtx);
1183
#endif /* #ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT */
1190
ethr_time_now(ethr_timeval *time)
1195
if (ethr_not_inited) {
1205
res = gettimeofday(&tv, NULL);
1206
time->tv_sec = (long) tv.tv_sec;
1207
time->tv_nsec = ((long) tv.tv_usec)*1000;
1212
* Thread specific data
1216
ethr_tsd_key_create(ethr_tsd_key *keyp)
1219
if (ethr_not_inited) {
1228
return pthread_key_create((pthread_key_t *) keyp, NULL);
1232
ethr_tsd_key_delete(ethr_tsd_key key)
1235
if (ethr_not_inited) {
1240
return pthread_key_delete((pthread_key_t) key);
1244
ethr_tsd_set(ethr_tsd_key key, void *value)
1247
if (ethr_not_inited) {
1252
return pthread_setspecific((pthread_key_t) key, value);
1256
ethr_tsd_get(ethr_tsd_key key)
1259
if (ethr_not_inited) {
1264
return pthread_getspecific((pthread_key_t) key);
1271
#if ETHR_HAVE_ETHR_SIG_FUNCS
1273
int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset)
1276
if (ethr_not_inited) {
1280
if (!set && !oset) {
1285
return pthread_sigmask(how, set, oset);
1288
int ethr_sigwait(const sigset_t *set, int *sig)
1291
if (ethr_not_inited) {
1300
if (sigwait(set, sig) < 0)
1305
#endif /* #if ETHR_HAVE_ETHR_SIG_FUNCS */
1307
#elif defined(ETHR_WIN32_THREADS)
1308
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
1309
* Native win32 threads implementation *
1312
#define INVALID_TID -1
1314
/* The spin count values are more or less taken out of the blue */
1315
#define ETHR_MUTEX_SPIN_COUNT 5000
1316
#define ETHR_COND_SPIN_COUNT 1000
1318
ethr_tid serial_shift; /* Bits to shift serial when constructing a tid */
1319
ethr_tid last_serial; /* Last thread table serial used */
1320
ethr_tid last_ix; /* Last thread table index used */
1321
ethr_tid thr_ix_mask; /* Mask used to mask out thread table index from a tid */
1323
/* Event used for conditional variables. On per thread. */
1324
/*typedef struct cnd_wait_event__ cnd_wait_event_;*/
1325
struct cnd_wait_event__ {
1327
cnd_wait_event_ *prev;
1328
cnd_wait_event_ *next;
1332
/* Thread specific data. Stored in the thread table */
1338
cnd_wait_event_ wait_event;
1341
/* Argument passed to thr_wrapper() */
1343
void * (*func)(void *);
1348
void *prep_func_res;
1352
static CRITICAL_SECTION thr_table_cs; /* Critical section used to protect
1353
the thread table from concurrent
1355
static CRITICAL_SECTION fake_static_init_cs; /* Critical section used to protect
1356
initialazition of 'statically
1357
initialized' mutexes */
1358
static thr_data_ * thr_table[ETHR_MAX_THREADS]; /* The thread table */
1360
static DWORD tls_own_thr_data;
1362
static thr_data_ main_thr_data;
1364
#define THR_IX(TID) ((TID) & thr_ix_mask)
1365
#define OWN_THR_DATA ((thr_data_ *) TlsGetValue(tls_own_thr_data))
1368
* ----------------------------------------------------------------------------
1370
* ----------------------------------------------------------------------------
1376
switch (GetLastError()) {
1377
case ERROR_INVALID_FUNCTION: return EINVAL; /* 1 */
1378
case ERROR_FILE_NOT_FOUND: return ENOENT; /* 2 */
1379
case ERROR_PATH_NOT_FOUND: return ENOENT; /* 3 */
1380
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; /* 4 */
1381
case ERROR_ACCESS_DENIED: return EACCES; /* 5 */
1382
case ERROR_INVALID_HANDLE: return EBADF; /* 6 */
1383
case ERROR_ARENA_TRASHED: return ENOMEM; /* 7 */
1384
case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; /* 8 */
1385
case ERROR_INVALID_BLOCK: return ENOMEM; /* 9 */
1386
case ERROR_BAD_ENVIRONMENT: return E2BIG; /* 10 */
1387
case ERROR_BAD_FORMAT: return ENOEXEC; /* 11 */
1388
case ERROR_INVALID_ACCESS: return EINVAL; /* 12 */
1389
case ERROR_INVALID_DATA: return EINVAL; /* 13 */
1390
case ERROR_OUTOFMEMORY: return ENOMEM; /* 14 */
1391
case ERROR_INVALID_DRIVE: return ENOENT; /* 15 */
1392
case ERROR_CURRENT_DIRECTORY: return EACCES; /* 16 */
1393
case ERROR_NOT_SAME_DEVICE: return EXDEV; /* 17 */
1394
case ERROR_NO_MORE_FILES: return ENOENT; /* 18 */
1395
case ERROR_WRITE_PROTECT: return EACCES; /* 19 */
1396
case ERROR_BAD_UNIT: return EACCES; /* 20 */
1397
case ERROR_NOT_READY: return EACCES; /* 21 */
1398
case ERROR_BAD_COMMAND: return EACCES; /* 22 */
1399
case ERROR_CRC: return EACCES; /* 23 */
1400
case ERROR_BAD_LENGTH: return EACCES; /* 24 */
1401
case ERROR_SEEK: return EACCES; /* 25 */
1402
case ERROR_NOT_DOS_DISK: return EACCES; /* 26 */
1403
case ERROR_SECTOR_NOT_FOUND: return EACCES; /* 27 */
1404
case ERROR_OUT_OF_PAPER: return EACCES; /* 28 */
1405
case ERROR_WRITE_FAULT: return EACCES; /* 29 */
1406
case ERROR_READ_FAULT: return EACCES; /* 30 */
1407
case ERROR_GEN_FAILURE: return EACCES; /* 31 */
1408
case ERROR_SHARING_VIOLATION: return EACCES; /* 32 */
1409
case ERROR_LOCK_VIOLATION: return EACCES; /* 33 */
1410
case ERROR_WRONG_DISK: return EACCES; /* 34 */
1411
case ERROR_SHARING_BUFFER_EXCEEDED: return EACCES; /* 36 */
1412
case ERROR_BAD_NETPATH: return ENOENT; /* 53 */
1413
case ERROR_NETWORK_ACCESS_DENIED: return EACCES; /* 65 */
1414
case ERROR_BAD_NET_NAME: return ENOENT; /* 67 */
1415
case ERROR_FILE_EXISTS: return EEXIST; /* 80 */
1416
case ERROR_CANNOT_MAKE: return EACCES; /* 82 */
1417
case ERROR_FAIL_I24: return EACCES; /* 83 */
1418
case ERROR_INVALID_PARAMETER: return EINVAL; /* 87 */
1419
case ERROR_NO_PROC_SLOTS: return EAGAIN; /* 89 */
1420
case ERROR_DRIVE_LOCKED: return EACCES; /* 108 */
1421
case ERROR_BROKEN_PIPE: return EPIPE; /* 109 */
1422
case ERROR_DISK_FULL: return ENOSPC; /* 112 */
1423
case ERROR_INVALID_TARGET_HANDLE: return EBADF; /* 114 */
1424
case ERROR_WAIT_NO_CHILDREN: return ECHILD; /* 128 */
1425
case ERROR_CHILD_NOT_COMPLETE: return ECHILD; /* 129 */
1426
case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; /* 130 */
1427
case ERROR_NEGATIVE_SEEK: return EINVAL; /* 131 */
1428
case ERROR_SEEK_ON_DEVICE: return EACCES; /* 132 */
1429
case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY;/* 145 */
1430
case ERROR_NOT_LOCKED: return EACCES; /* 158 */
1431
case ERROR_BAD_PATHNAME: return ENOENT; /* 161 */
1432
case ERROR_MAX_THRDS_REACHED: return EAGAIN; /* 164 */
1433
case ERROR_LOCK_FAILED: return EACCES; /* 167 */
1434
case ERROR_ALREADY_EXISTS: return EEXIST; /* 183 */
1435
case ERROR_INVALID_STARTING_CODESEG: return ENOEXEC; /* 188 */
1436
case ERROR_INVALID_STACKSEG: return ENOEXEC; /* 189 */
1437
case ERROR_INVALID_MODULETYPE: return ENOEXEC; /* 190 */
1438
case ERROR_INVALID_EXE_SIGNATURE: return ENOEXEC; /* 191 */
1439
case ERROR_EXE_MARKED_INVALID: return ENOEXEC; /* 192 */
1440
case ERROR_BAD_EXE_FORMAT: return ENOEXEC; /* 193 */
1441
case ERROR_ITERATED_DATA_EXCEEDS_64k: return ENOEXEC; /* 194 */
1442
case ERROR_INVALID_MINALLOCSIZE: return ENOEXEC; /* 195 */
1443
case ERROR_DYNLINK_FROM_INVALID_RING: return ENOEXEC; /* 196 */
1444
case ERROR_IOPL_NOT_ENABLED: return ENOEXEC; /* 197 */
1445
case ERROR_INVALID_SEGDPL: return ENOEXEC; /* 198 */
1446
case ERROR_AUTODATASEG_EXCEEDS_64k: return ENOEXEC; /* 199 */
1447
case ERROR_RING2SEG_MUST_BE_MOVABLE: return ENOEXEC; /* 200 */
1448
case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: return ENOEXEC; /* 201 */
1449
case ERROR_INFLOOP_IN_RELOC_CHAIN: return ENOEXEC; /* 202 */
1450
case ERROR_FILENAME_EXCED_RANGE: return ENOENT; /* 206 */
1451
case ERROR_NESTING_NOT_ALLOWED: return EAGAIN; /* 215 */
1452
case ERROR_NOT_ENOUGH_QUOTA: return ENOMEM; /* 1816 */
1453
default: return EINVAL;
1457
static ETHR_INLINE thr_data_ *
1458
tid2thr(ethr_tid tid)
1466
if (ix >= ETHR_MAX_THREADS)
1471
if (td->thr_id != tid)
1476
static ETHR_INLINE void
1477
new_tid(ethr_tid *new_tid, ethr_tid *new_serial, ethr_tid *new_ix)
1479
ethr_tid tmp_serial = last_serial;
1480
ethr_tid tmp_ix = last_ix + 1;
1481
ethr_tid start_ix = tmp_ix;
1485
if (tmp_ix >= ETHR_MAX_THREADS) {
1487
if ((tmp_serial << serial_shift) < 0)
1491
if (!thr_table[tmp_ix]) {
1492
*new_tid = (tmp_serial << serial_shift) | tmp_ix;
1493
*new_serial = tmp_serial;
1498
} while (tmp_ix != start_ix);
1500
*new_tid = INVALID_TID;
1501
*new_serial = INVALID_TID;
1502
*new_ix = INVALID_TID;
1507
static void thr_exit_cleanup(thr_data_ *td, void *res)
1510
ASSERT(td == OWN_THR_DATA);
1512
run_exit_handlers();
1514
EnterCriticalSection(&thr_table_cs);
1515
CloseHandle(td->wait_event.handle);
1516
if (td->thr_handle == INVALID_HANDLE_VALUE) {
1517
/* We are detached; cleanup thread table */
1518
ASSERT(td->joiner == INVALID_TID);
1519
ASSERT(td == thr_table[THR_IX(td->thr_id)]);
1520
thr_table[THR_IX(td->thr_id)] = NULL;
1521
if (td != &main_thr_data)
1522
(*freep)((void *) td);
1525
/* Save result and let joining thread cleanup */
1528
LeaveCriticalSection(&thr_table_cs);
1531
static unsigned __stdcall thr_wrapper(LPVOID args)
1533
void *(*func)(void*) = ((thr_wrap_data_ *) args)->func;
1534
void *arg = ((thr_wrap_data_ *) args)->arg;
1535
thr_data_ *td = ((thr_wrap_data_ *) args)->td;
1537
td->wait_event.handle = CreateEvent(NULL, FALSE, FALSE, NULL);
1538
if (td->wait_event.handle == INVALID_HANDLE_VALUE
1539
|| !TlsSetValue(tls_own_thr_data, (LPVOID) td)) {
1540
((thr_wrap_data_ *) args)->res = get_errno();
1541
if (td->wait_event.handle != INVALID_HANDLE_VALUE)
1542
CloseHandle(td->wait_event.handle);
1543
SetEvent(((thr_wrap_data_ *) args)->ptd->wait_event.handle);
1544
_endthreadex((unsigned) 0);
1548
td->wait_event.prev = NULL;
1549
td->wait_event.next = NULL;
1550
td->wait_event.in_queue = 0;
1552
if (thread_create_child_func)
1553
(*thread_create_child_func)(((thr_wrap_data_ *) args)->prep_func_res);
1555
ASSERT(td == OWN_THR_DATA);
1557
((thr_wrap_data_ *) args)->res = 0;
1558
SetEvent(((thr_wrap_data_ *) args)->ptd->wait_event.handle);
1560
thr_exit_cleanup(td, (*func)(arg));
1565
ethr_fake_static_mutex_init(ethr_mutex *mtx)
1567
EnterCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
1568
/* Got here under race conditions; check again... */
1569
if (!mtx->initialized) {
1570
if (!InitializeCriticalSectionAndSpinCount(&mtx->cs,
1571
ETHR_MUTEX_SPIN_COUNT))
1573
mtx->initialized = ETHR_MUTEX_INITIALIZED;
1575
LeaveCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
1580
fake_static_cond_init(ethr_cond *cnd)
1582
EnterCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
1583
/* Got here under race conditions; check again... */
1584
if (!cnd->initialized) {
1585
if (!InitializeCriticalSectionAndSpinCount(&cnd->cs,
1586
ETHR_COND_SPIN_COUNT))
1589
cnd->queue_end = NULL;
1590
cnd->initialized = ETHR_COND_INITIALIZED;
1592
LeaveCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
1597
#define LL_LITERAL(X) X##LL
1599
#define LL_LITERAL(X) X##i64
1602
#define EPOCH_JULIAN_DIFF LL_LITERAL(11644473600)
1604
static ETHR_INLINE void
1605
get_curr_time(long *sec, long *nsec)
1612
SystemTimeToFileTime(&t, &ft);
1613
memcpy(&lft, &ft, sizeof(lft));
1614
*nsec = ((long) (lft % LL_LITERAL(10000000)))*100;
1615
*sec = (long) ((lft / LL_LITERAL(10000000)) - EPOCH_JULIAN_DIFF);
1618
static cnd_wait_event_ *cwe_freelist;
1619
static CRITICAL_SECTION cwe_cs;
1622
alloc_cwe(cnd_wait_event_ **cwe_res)
1624
cnd_wait_event_ *cwe;
1625
EnterCriticalSection(&cwe_cs);
1628
cwe_freelist = cwe->next;
1629
LeaveCriticalSection(&cwe_cs);
1632
LeaveCriticalSection(&cwe_cs);
1633
cwe = (*allocp)(sizeof(cnd_wait_event_));
1636
cwe->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
1637
if (cwe->handle == INVALID_HANDLE_VALUE) {
1638
int res = get_errno();
1648
free_cwe(cnd_wait_event_ *cwe)
1650
EnterCriticalSection(&cwe_cs);
1651
cwe->next = cwe_freelist;
1653
LeaveCriticalSection(&cwe_cs);
1656
static ETHR_INLINE int
1657
condwait(ethr_cond *cnd,
1660
ethr_timeval *timeout)
1664
cnd_wait_event_ *cwe;
1666
long time; /* time until timeout in milli seconds */
1669
if (ethr_not_inited) {
1675
|| mtx->initialized != ETHR_MUTEX_INITIALIZED
1677
|| (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)
1678
|| (with_timeout && !timeout)) {
1686
cwe = &td->wait_event;
1687
else { /* A non-ethread thread */
1688
res = alloc_cwe(&cwe);
1693
if (!cnd->initialized)
1694
fake_static_cond_init(cnd);
1695
EnterCriticalSection(&cnd->cs);
1697
ASSERT(!cwe->in_queue);
1698
if (cnd->queue_end) {
1700
cwe->prev = cnd->queue_end;
1702
cnd->queue_end->next = cwe;
1703
cnd->queue_end = cwe;
1706
ASSERT(!cnd->queue);
1710
cnd->queue_end = cwe;
1714
LeaveCriticalSection(&cnd->cs);
1716
LeaveCriticalSection(&mtx->cs);
1723
get_curr_time(&sec, &nsec);
1724
time = (timeout->tv_sec - sec)*1000;
1725
time += (timeout->tv_nsec - nsec + 500)/1000000;
1730
/* wait for event to signal */
1731
code = WaitForSingleObject(cwe->handle, time);
1733
EnterCriticalSection(&mtx->cs);
1735
if (code == WAIT_OBJECT_0) {
1736
/* We were woken by a signal or a broadcast ... */
1739
/* ... no need to remove event from wait queue since this was
1740
taken care of by the signal or broadcast */
1742
EnterCriticalSection(&cnd->cs);
1743
ASSERT(!cwe->in_queue);
1744
LeaveCriticalSection(&cnd->cs);
1749
/* We timed out... */
1752
/* ... probably have to remove event from wait queue ... */
1753
EnterCriticalSection(&cnd->cs);
1755
if (cwe->in_queue) { /* ... but we must check that we are in queue
1756
since a signal or broadcast after timeout
1757
may have removed us from the queue */
1759
cwe->prev->next = cwe->next;
1762
ASSERT(cnd->queue == cwe);
1763
cnd->queue = cwe->next;
1767
cwe->next->prev = cwe->prev;
1770
ASSERT(cnd->queue_end == cwe);
1771
cnd->queue_end = cwe->prev;
1776
LeaveCriticalSection(&cnd->cs);
1789
* ----------------------------------------------------------------------------
1790
* Exported functions
1791
* ----------------------------------------------------------------------------
1795
ethr_init(ethr_init_data *id)
1798
DWORD major = (_WIN32_WINNT >> 8) & 0xff;
1799
DWORD minor = _WIN32_WINNT & 0xff;
1800
OSVERSIONINFO os_version;
1803
thr_data_ *td = &main_thr_data;
1806
if (!ethr_not_inited)
1810
os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1811
GetVersionEx(&os_version);
1812
if (os_version.dwPlatformId != VER_PLATFORM_WIN32_NT
1813
|| os_version.dwMajorVersion < major
1814
|| (os_version.dwMajorVersion == major
1815
&& os_version.dwMinorVersion < minor))
1819
ASSERT(ETHR_MAX_THREADS > 0);
1820
for (i = ETHR_MAX_THREADS - 1, serial_shift = 0;
1822
serial_shift++, i >>= 1);
1823
thr_ix_mask = ~(~((ethr_tid) 0) << serial_shift);
1825
tls_own_thr_data = TlsAlloc();
1826
if (tls_own_thr_data == TLS_OUT_OF_INDEXES)
1833
td->thr_handle = GetCurrentThread();
1834
td->joiner = INVALID_TID;
1836
td->wait_event.handle = CreateEvent(NULL, FALSE, FALSE, NULL);
1837
if (td->wait_event.handle == INVALID_HANDLE_VALUE)
1839
td->wait_event.prev = NULL;
1840
td->wait_event.next = NULL;
1841
td->wait_event.in_queue = 0;
1844
if (!TlsSetValue(tls_own_thr_data, (LPVOID) td))
1847
ASSERT(td == OWN_THR_DATA);
1850
cwe_freelist = NULL;
1851
if (!InitializeCriticalSectionAndSpinCount(&cwe_cs,
1852
ETHR_MUTEX_SPIN_COUNT))
1855
for (i = 1; i < ETHR_MAX_THREADS; i++)
1856
thr_table[i] = NULL;
1858
if (!InitializeCriticalSectionAndSpinCount(&thr_table_cs,
1859
ETHR_MUTEX_SPIN_COUNT))
1861
if (!InitializeCriticalSectionAndSpinCount(&fake_static_init_cs,
1862
ETHR_MUTEX_SPIN_COUNT))
1864
ethr_not_inited = 0;
1866
err = init_common(id);
1873
ethr_not_inited = 1;
1877
if (td->thr_handle != INVALID_HANDLE_VALUE)
1878
CloseHandle(td->thr_handle);
1879
if (td->wait_event.handle != INVALID_HANDLE_VALUE)
1880
CloseHandle(td->wait_event.handle);
1889
ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg,
1890
ethr_thr_opts *opts)
1894
thr_data_ *my_td, *child_td = NULL;
1895
ethr_tid child_tid, child_serial, child_ix;
1898
unsigned stack_size = 0; /* 0 = system default */
1899
int use_stack_size = (opts && opts->suggested_stack_size >= 0
1900
? opts->suggested_stack_size
1901
: -1 /* Use system default */);
1903
#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
1904
if (use_stack_size < 0)
1905
use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
1909
if (ethr_not_inited) {
1913
if (!tid || !func) {
1919
my_td = OWN_THR_DATA;
1921
/* Only ethreads are allowed to call this function */
1926
if (use_stack_size >= 0) {
1927
size_t suggested_stack_size = (size_t) use_stack_size;
1929
suggested_stack_size /= 2; /* Make sure we got margin */
1931
if (suggested_stack_size < min_stack_size)
1932
stack_size = (unsigned) ETHR_KW2B(min_stack_size);
1933
else if (suggested_stack_size > max_stack_size)
1934
stack_size = (unsigned) ETHR_KW2B(max_stack_size);
1937
(unsigned) ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
1940
EnterCriticalSection(&thr_table_cs);
1942
/* Call prepare func if it exist */
1943
if (thread_create_prepare_func)
1944
twd.prep_func_res = (*thread_create_prepare_func)();
1946
twd.prep_func_res = NULL;
1948
/* Find a new thread id to use */
1949
new_tid(&child_tid, &child_serial, &child_ix);
1950
if (child_tid == INVALID_TID) {
1955
ASSERT(child_ix == THR_IX(child_tid));
1959
ASSERT(!thr_table[child_ix]);
1961
/* Alloc thread data */
1962
thr_table[child_ix] = child_td = (thr_data_ *) (*allocp)(sizeof(thr_data_));
1968
/* Init thread data */
1970
child_td->thr_id = child_tid;
1971
child_td->thr_handle = INVALID_HANDLE_VALUE;
1972
child_td->joiner = INVALID_TID;
1973
child_td->result = NULL;
1974
/* 'child_td->wait_event' is initialized by child thread */
1977
/* Init thread wrapper data */
1985
ASSERT(!my_td->wait_event.in_queue);
1987
/* spawn the thr_wrapper function */
1988
child_td->thr_handle = (HANDLE) _beginthreadex(NULL,
1994
if (child_td->thr_handle == (HANDLE) 0) {
1995
child_td->thr_handle = INVALID_HANDLE_VALUE;
1999
ASSERT(child_td->thr_handle != INVALID_HANDLE_VALUE);
2001
/* Wait for child to finish initialization */
2002
code = WaitForSingleObject(my_td->wait_event.handle, INFINITE);
2003
if (twd.res || code != WAIT_OBJECT_0) {
2008
if (opts && opts->detached) {
2009
CloseHandle(child_td->thr_handle);
2010
child_td->thr_handle = INVALID_HANDLE_VALUE;
2013
last_serial = child_serial;
2016
ASSERT(thr_table[child_ix] == child_td);
2018
if (thread_create_parent_func)
2019
(*thread_create_parent_func)(twd.prep_func_res);
2021
LeaveCriticalSection(&thr_table_cs);
2031
if (thread_create_parent_func)
2032
(*thread_create_parent_func)(twd.prep_func_res);
2034
if (child_ix != INVALID_TID) {
2037
ASSERT(thr_table[child_ix] == child_td);
2039
if (child_td->thr_handle != INVALID_HANDLE_VALUE) {
2040
WaitForSingleObject(child_td->thr_handle, INFINITE);
2041
CloseHandle(child_td->thr_handle);
2044
(*freep)((void *) child_td);
2045
thr_table[child_ix] = NULL;
2051
LeaveCriticalSection(&thr_table_cs);
2055
int ethr_thr_join(ethr_tid tid, void **res)
2063
if (ethr_not_inited) {
2069
my_td = OWN_THR_DATA;
2072
/* Only ethreads are allowed to call this function */
2077
EnterCriticalSection(&thr_table_cs);
2082
else if (td->thr_handle == INVALID_HANDLE_VALUE /* i.e. detached */
2083
|| td->joiner != INVALID_TID) /* i.e. someone else is joining */
2085
else if (my_td == td)
2088
td->joiner = my_td->thr_id;
2090
LeaveCriticalSection(&thr_table_cs);
2095
/* Wait for thread to terminate */
2096
code = WaitForSingleObject(td->thr_handle, INFINITE);
2097
if (code != WAIT_OBJECT_0)
2100
EnterCriticalSection(&thr_table_cs);
2102
ASSERT(td == tid2thr(tid));
2103
ASSERT(td->thr_handle != INVALID_HANDLE_VALUE);
2104
ASSERT(td->joiner == my_td->thr_id);
2109
CloseHandle(td->thr_handle);
2110
ASSERT(td == thr_table[THR_IX(td->thr_id)]);
2111
thr_table[THR_IX(td->thr_id)] = NULL;
2112
if (td != &main_thr_data)
2113
(*freep)((void *) td);
2115
LeaveCriticalSection(&thr_table_cs);
2128
ethr_thr_detach(ethr_tid tid)
2135
if (ethr_not_inited) {
2141
if (!OWN_THR_DATA) {
2142
/* Only ethreads are allowed to call this function */
2147
EnterCriticalSection(&thr_table_cs);
2152
if (td->thr_handle == INVALID_HANDLE_VALUE /* i.e. detached */
2153
|| td->joiner != INVALID_TID) /* i.e. someone is joining */
2157
CloseHandle(td->thr_handle);
2158
td->thr_handle = INVALID_HANDLE_VALUE;
2161
LeaveCriticalSection(&thr_table_cs);
2168
ethr_thr_exit(void *res)
2172
if (ethr_not_inited) {
2179
/* Only ethreads are allowed to call this function */
2183
thr_exit_cleanup(td, res);
2184
_endthreadex((unsigned) 0);
2192
if (ethr_not_inited) {
2197
/* It is okay for non-ethreads (i.e. native win32 threads) to call
2198
ethr_self(). They will however be returned the INVALID_TID. */
2206
ethr_equal_tids(ethr_tid tid1, ethr_tid tid2)
2208
/* INVALID_TID does not equal any tid, not even the INVALID_TID */
2209
return tid1 == tid2 && tid1 != INVALID_TID;
2217
ethr_mutex_init(ethr_mutex *mtx)
2220
if (ethr_not_inited) {
2229
if (!InitializeCriticalSectionAndSpinCount(&mtx->cs, ETHR_MUTEX_SPIN_COUNT))
2231
mtx->initialized = ETHR_MUTEX_INITIALIZED;
2233
mtx->is_rec_mtx = 0;
2239
ethr_rec_mutex_init(ethr_mutex *mtx)
2242
res = ethr_mutex_init(mtx);
2244
mtx->is_rec_mtx = 1;
2250
ethr_mutex_destroy(ethr_mutex *mtx)
2253
if (ethr_not_inited) {
2257
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
2262
DeleteCriticalSection(&mtx->cs);
2263
mtx->initialized = 0;
2267
int ethr_mutex_set_forksafe(ethr_mutex *mtx)
2270
if (ethr_not_inited) {
2275
return 0; /* No fork() */
2278
int ethr_mutex_unset_forksafe(ethr_mutex *mtx)
2281
if (ethr_not_inited) {
2286
return 0; /* No fork() */
2290
ethr_mutex_trylock(ethr_mutex *mtx)
2293
if (ethr_not_inited) {
2298
|| (mtx->initialized && mtx->initialized != ETHR_MUTEX_INITIALIZED)) {
2303
if (!mtx->initialized) {
2304
int res = ethr_fake_static_mutex_init(mtx);
2308
return ethr_mutex_trylock__(mtx);
2312
ethr_mutex_lock(ethr_mutex *mtx)
2316
if (ethr_not_inited) {
2321
|| (mtx->initialized && mtx->initialized != ETHR_MUTEX_INITIALIZED)) {
2326
return ethr_mutex_lock__(mtx);
2330
ethr_mutex_unlock(ethr_mutex *mtx)
2334
if (ethr_not_inited) {
2338
if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
2343
return ethr_mutex_unlock__(mtx);
2347
* Condition variable functions.
2351
ethr_cond_init(ethr_cond *cnd)
2354
if (ethr_not_inited) {
2363
if (!InitializeCriticalSectionAndSpinCount(&cnd->cs, ETHR_COND_SPIN_COUNT))
2366
cnd->queue_end = NULL;
2367
cnd->initialized = ETHR_COND_INITIALIZED;
2372
ethr_cond_destroy(ethr_cond *cnd)
2375
if (ethr_not_inited) {
2380
|| (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)
2386
DeleteCriticalSection(&cnd->cs);
2387
cnd->initialized = 0;
2392
ethr_cond_signal(ethr_cond *cnd)
2394
cnd_wait_event_ *cwe;
2396
if (ethr_not_inited) {
2401
|| (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)) {
2406
if (!cnd->initialized) {
2407
int res = fake_static_cond_init(cnd);
2411
EnterCriticalSection(&cnd->cs);
2414
ASSERT(cwe->in_queue);
2415
SetEvent(cnd->queue->handle);
2417
cwe->next->prev = NULL;
2419
ASSERT(cnd->queue_end == cnd->queue);
2420
cnd->queue_end = NULL;
2422
cnd->queue = cwe->next;
2425
LeaveCriticalSection(&cnd->cs);
2430
ethr_cond_broadcast(ethr_cond *cnd)
2432
cnd_wait_event_ *cwe;
2435
if (ethr_not_inited) {
2440
|| (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)) {
2445
if (!cnd->initialized) {
2446
int res = fake_static_cond_init(cnd);
2450
EnterCriticalSection(&cnd->cs);
2451
for (cwe = cnd->queue; cwe; cwe = cwe->next) {
2452
ASSERT(cwe->in_queue);
2453
SetEvent(cwe->handle);
2457
cnd->queue_end = NULL;
2458
LeaveCriticalSection(&cnd->cs);
2464
ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
2466
return condwait(cnd, mtx, 0, NULL);
2470
ethr_cond_timedwait(ethr_cond *cnd, ethr_mutex *mtx, ethr_timeval *timeout)
2472
return condwait(cnd, mtx, 1, timeout);
2476
ethr_time_now(ethr_timeval *time)
2479
if (ethr_not_inited) {
2488
get_curr_time(&time->tv_sec, &time->tv_nsec);
2493
* Thread specific data
2497
ethr_tsd_key_create(ethr_tsd_key *keyp)
2501
if (ethr_not_inited) {
2511
if (key == TLS_OUT_OF_INDEXES)
2513
*keyp = (ethr_tsd_key) key;
2518
ethr_tsd_key_delete(ethr_tsd_key key)
2521
if (ethr_not_inited) {
2526
if (!TlsFree((DWORD) key))
2532
ethr_tsd_set(ethr_tsd_key key, void *value)
2535
if (ethr_not_inited) {
2540
if (!TlsSetValue((DWORD) key, (LPVOID) value))
2546
ethr_tsd_get(ethr_tsd_key key)
2549
if (ethr_not_inited) {
2554
return (void *) TlsGetValue((DWORD) key);
2559
#ifndef ETHR_HAVE_OPTIMIZED_LOCKS
2562
ethr_do_spinlock_init(ethr_spinlock_t *lock)
2565
if (ethr_not_inited) {
2574
if (InitializeCriticalSectionAndSpinCount(&lock->cs, INT_MAX))
2581
ethr_do_rwlock_init(ethr_rwlock_t *lock)
2584
if (ethr_not_inited) {
2594
if (InitializeCriticalSectionAndSpinCount(&lock->cs, INT_MAX))
2600
#endif /* #ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS */
2603
#error "Missing thread implementation"
2609
ethr_atomic_init(ethr_atomic_t *var, long i)
2612
if (ethr_not_inited) {
2621
return ethr_atomic_init__(var, i);
2625
ethr_atomic_set(ethr_atomic_t *var, long i)
2628
if (ethr_not_inited) {
2637
return ethr_atomic_set__(var, i);
2641
ethr_atomic_read(ethr_atomic_t *var, long *i)
2644
if (ethr_not_inited) {
2653
return ethr_atomic_read__(var, i);
2658
ethr_atomic_addtest(ethr_atomic_t *var, long incr, long *testp)
2661
if (ethr_not_inited) {
2665
if (!var || !testp) {
2670
return ethr_atomic_addtest__(var, incr, testp);
2674
ethr_atomic_inctest(ethr_atomic_t *incp, long *testp)
2677
if (ethr_not_inited) {
2681
if (!incp || !testp) {
2686
return ethr_atomic_inctest__(incp, testp);
2690
ethr_atomic_dectest(ethr_atomic_t *decp, long *testp)
2693
if (ethr_not_inited) {
2697
if (!decp || !testp) {
2702
return ethr_atomic_dectest__(decp, testp);
2706
ethr_atomic_add(ethr_atomic_t *var, long incr)
2709
if (ethr_not_inited) {
2718
return ethr_atomic_add__(var, incr);
2722
ethr_atomic_inc(ethr_atomic_t *incp)
2725
if (ethr_not_inited) {
2734
return ethr_atomic_inc__(incp);
2738
ethr_atomic_dec(ethr_atomic_t *decp)
2741
if (ethr_not_inited) {
2750
return ethr_atomic_dec__(decp);
2754
ethr_atomic_and_old(ethr_atomic_t *var, long mask, long *old)
2757
if (ethr_not_inited) {
2766
return ethr_atomic_and_old__(var, mask, old);
2770
ethr_atomic_or_old(ethr_atomic_t *var, long mask, long *old)
2773
if (ethr_not_inited) {
2782
return ethr_atomic_or_old__(var, mask, old);
2786
ethr_atomic_xchg(ethr_atomic_t *var, long new, long *old)
2789
if (ethr_not_inited) {
2798
return ethr_atomic_xchg__(var, new, old);
2802
ethr_atomic_cmpxchg(ethr_atomic_t *var, long new, long expected, long *old)
2805
if (ethr_not_inited) {
2814
return ethr_atomic_cmpxchg__(var, new, expected, old);
2817
/* Spinlocks and rwspinlocks */
2820
ethr_spinlock_init(ethr_spinlock_t *lock)
2823
if (ethr_not_inited) {
2832
return ethr_spinlock_init__(lock);
2836
ethr_spinlock_destroy(ethr_spinlock_t *lock)
2839
if (ethr_not_inited) {
2848
return ethr_spinlock_destroy__(lock);
2853
ethr_spin_unlock(ethr_spinlock_t *lock)
2856
if (ethr_not_inited) {
2865
return ethr_spin_unlock__(lock);
2869
ethr_spin_lock(ethr_spinlock_t *lock)
2872
if (ethr_not_inited) {
2881
return ethr_spin_lock__(lock);
2885
ethr_rwlock_init(ethr_rwlock_t *lock)
2888
if (ethr_not_inited) {
2897
return ethr_rwlock_init__(lock);
2901
ethr_rwlock_destroy(ethr_rwlock_t *lock)
2904
if (ethr_not_inited) {
2913
return ethr_rwlock_destroy__(lock);
2917
ethr_read_unlock(ethr_rwlock_t *lock)
2920
if (ethr_not_inited) {
2929
return ethr_read_unlock__(lock);
2933
ethr_read_lock(ethr_rwlock_t *lock)
2936
if (ethr_not_inited) {
2945
return ethr_read_lock__(lock);
2949
ethr_write_unlock(ethr_rwlock_t *lock)
2952
if (ethr_not_inited) {
2961
return ethr_write_unlock__(lock);
2965
ethr_write_lock(ethr_rwlock_t *lock)
2968
if (ethr_not_inited) {
2977
return ethr_write_lock__(lock);
2982
ethr_gate_init(ethr_gate *gp)
2986
if (ethr_not_inited) {
2995
res = ethr_mutex_init(&gp->mtx);
2998
res = ethr_cond_init(&gp->cnd);
3000
ethr_mutex_destroy(&gp->mtx);
3008
ethr_gate_destroy(ethr_gate *gp)
3012
if (ethr_not_inited) {
3021
res = ethr_mutex_destroy(&gp->mtx);
3022
dres = ethr_cond_destroy(&gp->cnd);
3030
ethr_gate_close(ethr_gate *gp)
3034
if (ethr_not_inited) {
3043
res = ethr_mutex_lock__(&gp->mtx);
3047
res = ethr_mutex_unlock__(&gp->mtx);
3052
ethr_gate_let_through(ethr_gate *gp, unsigned no)
3056
if (ethr_not_inited) {
3065
res = ethr_mutex_lock__(&gp->mtx);
3069
res = (gp->open == 1
3070
? ethr_cond_signal(&gp->cnd)
3071
: ethr_cond_broadcast(&gp->cnd));
3072
ures = ethr_mutex_unlock__(&gp->mtx);
3079
ethr_gate_swait(ethr_gate *gp, int spincount)
3083
if (ethr_not_inited) {
3093
res = ethr_mutex_lock__(&gp->mtx);
3096
while (n >= 0 && !gp->open) {
3097
res = ethr_mutex_unlock__(&gp->mtx);
3100
res = ethr_mutex_lock__(&gp->mtx);
3106
res = ethr_cond_wait(&gp->cnd, &gp->mtx);
3107
if (res != 0 && res != EINTR)
3112
ures = ethr_mutex_unlock__(&gp->mtx);
3120
ethr_gate_wait(ethr_gate *gp)
3122
return ethr_gate_swait(gp, 0);
3126
/* rwmutex fallback */
3127
#ifdef ETHR_USE_RWMTX_FALLBACK
3130
ethr_rwmutex_init(ethr_rwmutex *rwmtx)
3139
res = ethr_mutex_init(&rwmtx->mtx);
3142
ethr_cond_init(&rwmtx->rcnd);
3144
goto error_cleanup1;
3145
res = ethr_cond_init(&rwmtx->wcnd);
3147
goto error_cleanup2;
3149
rwmtx->waiting_readers = 0;
3150
rwmtx->waiting_writers = 0;
3152
rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
3156
ethr_cond_destroy(&rwmtx->rcnd);
3158
ethr_mutex_destroy(&rwmtx->mtx);
3163
ethr_rwmutex_destroy(ethr_rwmutex *rwmtx)
3167
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3171
rwmtx->initialized = 0;
3173
res = ethr_mutex_destroy(&rwmtx->mtx);
3174
pres = ethr_cond_destroy(&rwmtx->rcnd);
3177
pres = ethr_cond_destroy(&rwmtx->wcnd);
3184
ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
3188
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3193
res = ethr_mutex_trylock__(&rwmtx->mtx);
3196
if (!rwmtx->waiting_writers) {
3197
res = ethr_mutex_unlock__(&rwmtx->mtx);
3203
return ethr_mutex_unlock__(&rwmtx->mtx);
3207
ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
3211
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3216
res = ethr_mutex_lock__(&rwmtx->mtx);
3219
while (rwmtx->waiting_writers) {
3220
rwmtx->waiting_readers++;
3221
res = ethr_cond_wait(&rwmtx->rcnd, &rwmtx->mtx);
3222
rwmtx->waiting_readers--;
3223
if (res != 0 && res != EINTR) {
3224
(void) ethr_mutex_unlock__(&rwmtx->mtx);
3229
return ethr_mutex_unlock__(&rwmtx->mtx);
3233
ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
3237
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3242
res = ethr_mutex_lock__(&rwmtx->mtx);
3246
if (!rwmtx->readers && rwmtx->waiting_writers)
3247
res = ethr_cond_signal(&rwmtx->wcnd);
3248
ures = ethr_mutex_unlock__(&rwmtx->mtx);
3255
ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
3259
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3264
res = ethr_mutex_trylock__(&rwmtx->mtx);
3267
if (!rwmtx->readers && !rwmtx->waiting_writers)
3270
res = ethr_mutex_unlock__(&rwmtx->mtx);
3278
ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
3282
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3287
res = ethr_mutex_lock__(&rwmtx->mtx);
3290
if (!rwmtx->readers && !rwmtx->waiting_writers)
3293
while (rwmtx->readers) {
3294
rwmtx->waiting_writers++;
3295
res = ethr_cond_wait(&rwmtx->wcnd, &rwmtx->mtx);
3296
rwmtx->waiting_writers--;
3297
if (res != 0 && res != EINTR) {
3298
(void) ethr_rwmutex_rwunlock(rwmtx);
3306
ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
3310
if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
3316
if (rwmtx->waiting_writers)
3317
res = ethr_cond_signal(&rwmtx->wcnd);
3318
else if (rwmtx->waiting_readers)
3319
res = ethr_cond_broadcast(&rwmtx->rcnd);
3320
ures = ethr_mutex_unlock__(&rwmtx->mtx);
3326
#endif /* #ifdef ETHR_USE_RWMTX_FALLBACK */
3329
ethr_compiler_barrier(void)
3337
int ethr_assert_failed(char *f, int l, char *a)
3339
fprintf(stderr, "%s:%d: Assertion failed: %s\n", f, l, a);