41#include "winpthreads.h"
58 void *(* func)(
void *);
69volatile long _pthread_cancelling;
74pthread_once_t _pthread_tls_once;
78pthread_rwlock_t _pthread_key_lock;
79unsigned _pthread_key_max;
80unsigned _pthread_key_sch;
81void (**_pthread_key_dest)(
void *);
84#define pthread_cleanup_push(F, A)\
86 const _pthread_cleanup _pthread_cup = {(F), (A), pthread_self()->clean};\
88 pthread_self()->clean = (_pthread_cleanup *) &_pthread_cup;\
92#define pthread_cleanup_pop(E)\
93 (pthread_self()->clean = _pthread_cup.next, (E ? _pthread_cup.func(_pthread_cup.arg) : 0));}
95static void _pthread_once_cleanup(pthread_once_t *o)
100int pthread_once(pthread_once_t *o,
void (*func)(
void))
110 if (!_InterlockedCompareExchange(o, 2, 0))
113 pthread_cleanup_push((
void(*)(
void*))_pthread_once_cleanup, o);
115 pthread_cleanup_pop(0);
135static int _pthread_once_raw(pthread_once_t *o,
void (*func)(
void))
145 if (!_InterlockedCompareExchange(o, 2, 0))
168int pthread_mutex_lock(pthread_mutex_t *m)
170 EnterCriticalSection(m);
174int pthread_mutex_unlock(pthread_mutex_t *m)
176 LeaveCriticalSection(m);
180int pthread_mutex_trylock(pthread_mutex_t *m)
182 return TryEnterCriticalSection(m) ? 0 : EBUSY;
185int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a)
188 InitializeCriticalSection(m);
193int pthread_mutex_destroy(pthread_mutex_t *m)
195 DeleteCriticalSection(m);
199int pthread_equal(pthread_t t1, pthread_t t2)
204int pthread_rwlock_init(pthread_rwlock_t *l, pthread_rwlockattr_t *a)
207 InitializeSRWLock(l);
212int pthread_rwlock_destroy(pthread_rwlock_t *l)
218int pthread_rwlock_rdlock(pthread_rwlock_t *l)
220 pthread_testcancel();
221 AcquireSRWLockShared(l);
226int pthread_rwlock_wrlock(pthread_rwlock_t *l)
228 pthread_testcancel();
229 AcquireSRWLockExclusive(l);
234int pthread_rwlock_unlock(pthread_rwlock_t *l)
236 void *state = *(
void **)l;
238 if (state == (
void *)1)
241 ReleaseSRWLockExclusive(l);
246 ReleaseSRWLockShared(l);
252int pthread_rwlock_tryrdlock(pthread_rwlock_t *l)
255 void *state = *(
void **)l;
260 if (!_InterlockedCompareExchangePointer((
void *
volatile *)l, (
void *)0x11, NULL))
return 0;
265 if (state == (
void *)1)
return EBUSY;
268 if ((uintptr_t)state & 14)
return EBUSY;
270 if (_InterlockedCompareExchangePointer((
void *
volatile *)l, (
void *)((uintptr_t)state + 16), state) == state)
return 0;
275int pthread_rwlock_trywrlock(pthread_rwlock_t *l)
278 if (!_InterlockedCompareExchangePointer((
void *
volatile *)l, (
void *)1, NULL))
return 0;
283void pthread_tls_init(
void)
285 _pthread_tls = TlsAlloc();
288 if (_pthread_tls == TLS_OUT_OF_INDEXES) abort();
291static void _pthread_cleanup_dest(pthread_t t)
295 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
299 for (i = 0; i < t->keymax; i++)
301 void *val = t->keyval[i];
305 pthread_rwlock_rdlock(&_pthread_key_lock);
306 if ((uintptr_t) _pthread_key_dest[i] > 1)
310 _pthread_key_dest[i](val);
313 pthread_rwlock_unlock(&_pthread_key_lock);
322pthread_t pthread_self(
void)
326 _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
328 t = (
struct _pthread_v*)TlsGetValue(_pthread_tls);
341 t->p_state = PTHREAD_DEFAULT_ATTR;
344 t->h = GetCurrentThread();
347 TlsSetValue(_pthread_tls, t);
362static unsigned long long _pthread_time_in_ms(
void)
368 return tb.time * 1000 + tb.millitm;
371static unsigned long long _pthread_time_in_ms_from_timespec(
const struct timespec *ts)
373 unsigned long long t = ts->tv_sec * 1000;
374 t += ts->tv_nsec / 1000000;
379static unsigned long long _pthread_rel_time_in_ms(
const struct timespec *ts)
381 unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts);
382 unsigned long long t2 = _pthread_time_in_ms();
385 if (t1 < t2)
return 0;
389int pthread_rwlock_timedrdlock(pthread_rwlock_t *l,
const struct timespec *ts)
391 unsigned long long ct = _pthread_time_in_ms();
392 unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
394 pthread_testcancel();
400 if (!pthread_rwlock_tryrdlock(l))
return 0;
403 ct = _pthread_time_in_ms();
406 if (ct > t)
return ETIMEDOUT;
410int pthread_rwlock_timedwrlock(pthread_rwlock_t *l,
const struct timespec *ts)
412 unsigned long long ct = _pthread_time_in_ms();
413 unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
415 pthread_testcancel();
421 if (!pthread_rwlock_trywrlock(l))
return 0;
424 ct = _pthread_time_in_ms();
427 if (ct > t)
return ETIMEDOUT;
431int pthread_get_concurrency(
int *val)
433 *val = _pthread_concur;
437int pthread_set_concurrency(
int val)
439 _pthread_concur = val;
443int pthread_exit(
void *res)
445 pthread_t t = pthread_self();
449 _pthread_cleanup_dest(t);
455static void _pthread_invoke_cancel(
void)
459 _InterlockedDecrement(&_pthread_cancelling);
462 for (pcup = pthread_self()->clean; pcup; pcup = pcup->next)
464 pcup->func(pcup->arg);
467 pthread_exit(PTHREAD_CANCELED);
470void pthread_testcancel(
void)
472 if (_pthread_cancelling)
474 pthread_t t = pthread_self();
476 if (t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE))
478 _pthread_invoke_cancel();
484int pthread_cancel(pthread_t t)
486#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP)
487 if (t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS)
493 if (t->cancelled)
return ESRCH;
495 ctxt.ContextFlags = CONTEXT_CONTROL;
498 GetThreadContext(t->h, &ctxt);
500 ctxt.Rip = (uintptr_t) _pthread_invoke_cancel;
501#elif defined(_M_ARM64)
502 ctxt.Pc = (uintptr_t) _pthread_invoke_cancel;
504 ctxt.Eip = (uintptr_t) _pthread_invoke_cancel;
506 SetThreadContext(t->h, &ctxt);
512 _InterlockedIncrement(&_pthread_cancelling);
523 _InterlockedIncrement(&_pthread_cancelling);
529static unsigned _pthread_get_state(
pthread_attr_t *attr,
unsigned flag)
531 return attr->p_state & flag;
534static int _pthread_set_state(
pthread_attr_t *attr,
unsigned flag,
unsigned val)
536 if (~flag & val)
return EINVAL;
537 attr->p_state &= ~flag;
538 attr->p_state |= val;
545 attr->p_state = PTHREAD_DEFAULT_ATTR;
560 return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag);
565 *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED);
571 return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag);
576 *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED);
582 return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag);
587 *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM);
593 *stack = attr->stack;
605 *size = attr->s_size;
615#define pthread_attr_getguardsize(A, S) ENOTSUP
616#define pthread_attr_setgaurdsize(A, S) ENOTSUP
617#define pthread_attr_getschedparam(A, S) ENOTSUP
618#define pthread_attr_setschedparam(A, S) ENOTSUP
619#define pthread_attr_getschedpolicy(A, S) ENOTSUP
620#define pthread_attr_setschedpolicy(A, S) ENOTSUP
623int pthread_setcancelstate(
int state,
int *oldstate)
625 pthread_t t = pthread_self();
627 if ((state & PTHREAD_CANCEL_ENABLE) != state)
return EINVAL;
628 if (oldstate) *oldstate = t->p_state & PTHREAD_CANCEL_ENABLE;
629 t->p_state &= ~PTHREAD_CANCEL_ENABLE;
635int pthread_setcanceltype(
int type,
int *oldtype)
637 pthread_t t = pthread_self();
639 if ((type & PTHREAD_CANCEL_ASYNCHRONOUS) != type)
return EINVAL;
640 if (oldtype) *oldtype = t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS;
641 t->p_state &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
647unsigned __stdcall pthread_create_wrapper(
void *args)
651 _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
653 TlsSetValue(_pthread_tls, tv);
658 tv->ret_arg = tv->func(tv->ret_arg);
661 _pthread_cleanup_dest(tv);
665 while (tv->h == (HANDLE) -1)
672 if (!tv->h) free(tv);
677int pthread_create(pthread_t *th,
pthread_attr_t *attr,
void *(* func)(
void *),
void *arg)
691 tv->p_state = PTHREAD_DEFAULT_ATTR;
698 tv->p_state = attr->p_state;
699 ssize = (unsigned) attr->s_size;
705 tv->h = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0, NULL);
708 if (!tv->h)
return 1;
710 if (tv->p_state & PTHREAD_CREATE_DETACHED)
720int pthread_join(pthread_t t,
void **res)
724 pthread_testcancel();
726 WaitForSingleObject(tv->h, INFINITE);
730 if (res) *res = tv->ret_arg;
737int pthread_detach(pthread_t t)
753int pthread_mutexattr_init(pthread_mutexattr_t *a)
759int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
765int pthread_mutexattr_gettype(pthread_mutexattr_t *a,
int *type)
772int pthread_mutexattr_settype(pthread_mutexattr_t *a,
int type)
774 if ((
unsigned) type > 3)
return EINVAL;
781int pthread_mutexattr_getpshared(pthread_mutexattr_t *a,
int *type)
788int pthread_mutexattr_setpshared(pthread_mutexattr_t * a,
int type)
790 if ((type & 4) != type)
return EINVAL;
798int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a,
int *type)
800 *type = *a & (8 + 16);
805int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a,
int type)
807 if ((type & (8 + 16)) != 8 + 16)
return EINVAL;
815int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a,
int * prio)
817 *prio = *a / PTHREAD_PRIO_MULT;
821int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a,
int prio)
823 *a &= (PTHREAD_PRIO_MULT - 1);
824 *a += prio * PTHREAD_PRIO_MULT;
829int pthread_mutex_timedlock(pthread_mutex_t *m,
struct timespec *ts)
831 unsigned long long t, ct;
833 struct _pthread_crit_t
844 if (!pthread_mutex_trylock(m))
return 0;
846 ct = _pthread_time_in_ms();
847 t = _pthread_time_in_ms_from_timespec(ts);
852 if (ct > t)
return ETIMEDOUT;
855 WaitForSingleObject(((
struct _pthread_crit_t *)m)->sem, (DWORD)(t - ct));
858 if (!pthread_mutex_trylock(m))
return 0;
861 ct = _pthread_time_in_ms();
865#define _PTHREAD_BARRIER_FLAG (1<<30)
869 EnterCriticalSection(&b->m);
871 while (b->total > _PTHREAD_BARRIER_FLAG)
874 SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
877 LeaveCriticalSection(&b->m);
879 DeleteCriticalSection(&b->m);
892 InitializeCriticalSection(&b->m);
893 InitializeConditionVariable(&b->cv);
900 EnterCriticalSection(&b->m);
902 while (b->total > _PTHREAD_BARRIER_FLAG)
905 SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
909 if (b->total == _PTHREAD_BARRIER_FLAG) b->total = 0;
913 if (b->total == b->count)
915 b->total += _PTHREAD_BARRIER_FLAG - 1;
916 WakeAllConditionVariable(&b->cv);
918 LeaveCriticalSection(&b->m);
924 while (b->total < _PTHREAD_BARRIER_FLAG)
927 SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
933 if (b->total == _PTHREAD_BARRIER_FLAG) WakeAllConditionVariable(&b->cv);
935 LeaveCriticalSection(&b->m);
941int pthread_barrierattr_init(
void **attr)
947int pthread_barrierattr_destroy(
void **attr)
955int pthread_barrierattr_setpshared(
void **attr,
int s)
961int pthread_barrierattr_getpshared(
void **attr,
int *s)
963 *s = (int) (
size_t) *attr;
968int pthread_key_create(pthread_key_t *key,
void (* dest)(
void *))
974 if (!key)
return EINVAL;
976 pthread_rwlock_wrlock(&_pthread_key_lock);
978 for (i = _pthread_key_sch; i < _pthread_key_max; i++)
980 if (!_pthread_key_dest[i])
985 _pthread_key_dest[i] = dest;
989 _pthread_key_dest[i] = (void(*)(
void *))1;
991 pthread_rwlock_unlock(&_pthread_key_lock);
997 for (i = 0; i < _pthread_key_sch; i++)
999 if (!_pthread_key_dest[i])
1004 _pthread_key_dest[i] = dest;
1008 _pthread_key_dest[i] = (void(*)(
void *))1;
1010 pthread_rwlock_unlock(&_pthread_key_lock);
1016 if (!_pthread_key_max) _pthread_key_max = 1;
1017 if (_pthread_key_max == PTHREAD_KEYS_MAX)
1019 pthread_rwlock_unlock(&_pthread_key_lock);
1024 nmax = _pthread_key_max * 2;
1025 if (nmax > PTHREAD_KEYS_MAX) nmax = PTHREAD_KEYS_MAX;
1028 d = (void (**)(
void*))realloc(_pthread_key_dest, nmax *
sizeof(*d));
1031 pthread_rwlock_unlock(&_pthread_key_lock);
1037 memset((
void *) &d[_pthread_key_max], 0, (nmax-_pthread_key_max)*
sizeof(
void *));
1040 _pthread_key_dest = d;
1041 _pthread_key_sch = _pthread_key_max + 1;
1042 *key = _pthread_key_max;
1043 _pthread_key_max = nmax;
1047 _pthread_key_dest[*key] = dest;
1051 _pthread_key_dest[*key] = (void(*)(
void *))1;
1054 pthread_rwlock_unlock(&_pthread_key_lock);
1059int pthread_key_delete(pthread_key_t key)
1061 if (key > _pthread_key_max)
return EINVAL;
1062 if (!_pthread_key_dest)
return EINVAL;
1064 pthread_rwlock_wrlock(&_pthread_key_lock);
1065 _pthread_key_dest[key] = NULL;
1068 if (_pthread_key_sch > key) _pthread_key_sch = key;
1070 pthread_rwlock_unlock(&_pthread_key_lock);
1075void *pthread_getspecific(pthread_key_t key)
1077 pthread_t t = pthread_self();
1079 if (key >= t->keymax)
return NULL;
1081 return t->keyval[key];
1085int pthread_setspecific(pthread_key_t key,
const void *value)
1087 pthread_t t = pthread_self();
1089 if (key > t->keymax)
1091 int keymax = (key + 1) * 2;
1092 void **kv = (
void**)realloc(t->keyval, keymax *
sizeof(
void *));
1094 if (!kv)
return ENOMEM;
1097 memset(&kv[t->keymax], 0, (keymax - t->keymax)*
sizeof(
void*));
1103 t->keyval[key] = (
void *) value;
1109int pthread_spin_init(pthread_spinlock_t *l,
int pshared)
1117int pthread_spin_destroy(pthread_spinlock_t *l)
1124int pthread_spin_lock(pthread_spinlock_t *l)
1126 while (_InterlockedExchange(l, EBUSY))
1134 _ReadWriteBarrier();
1141int pthread_spin_trylock(pthread_spinlock_t *l)
1143 return _InterlockedExchange(l, EBUSY);
1146int pthread_spin_unlock(pthread_spinlock_t *l)
1149 _ReadWriteBarrier();
1156int pthread_cond_init(pthread_cond_t *c, pthread_condattr_t *a)
1160 InitializeConditionVariable(c);
1164int pthread_cond_signal(pthread_cond_t *c)
1166 WakeConditionVariable(c);
1170int pthread_cond_broadcast(pthread_cond_t *c)
1172 WakeAllConditionVariable(c);
1176int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
1178 pthread_testcancel();
1179 SleepConditionVariableCS(c, m, INFINITE);
1183int pthread_cond_destroy(pthread_cond_t *c)
1189int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m,
struct timespec *t)
1191 unsigned long long tm = _pthread_rel_time_in_ms(t);
1193 pthread_testcancel();
1195 if (!SleepConditionVariableCS(c, m, (DWORD)tm))
return ETIMEDOUT;
1198 if (!_pthread_rel_time_in_ms(t))
return ETIMEDOUT;
1203int pthread_condattr_destroy(pthread_condattr_t *a)
1209int pthread_condattr_init(pthread_condattr_t *a)
1215int pthread_condattr_getpshared(pthread_condattr_t *a,
int *s)
1221int pthread_condattr_setpshared(pthread_condattr_t *a,
int s)
1227int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a)
1233int pthread_rwlockattr_init(pthread_rwlockattr_t *a)
1239int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a,
int *s)
1245int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a,
int s)