CPPMyth
Library to interoperate with MythTV server
Loading...
Searching...
No Matches
winpthreads.c
1/*
2 * Posix Threads library for Microsoft Windows
3 *
4 * Use at own risk, there is no implied warranty to this code.
5 * It uses undocumented features of Microsoft Windows that can change
6 * at any time in the future.
7 *
8 * (C) 2010 Lockless Inc.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 *
15 * * Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * * Neither the name of Lockless Inc. nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/*
37 * Version 1.0.1 Released 2 Feb 2012
38 * Fixes pthread_barrier_destroy() to wait for threads to exit the barrier.
39 */
40
41#include "winpthreads.h"
42#include <sys/timeb.h>
43#include <setjmp.h>
44#include <intrin.h>
45#include <process.h>
46
49{
50 void (*func)(void *);
51 void *arg;
52 _pthread_cleanup *next;
53};
54
56{
57 void *ret_arg;
58 void *(* func)(void *);
59 _pthread_cleanup *clean;
60 HANDLE h;
61 int cancelled;
62 unsigned p_state;
63 unsigned keymax;
64 void **keyval;
65
66 jmp_buf jb;
67};
68
69volatile long _pthread_cancelling;
70
71int _pthread_concur;
72
73/* Will default to zero as needed */
74pthread_once_t _pthread_tls_once;
75DWORD _pthread_tls;
76
77/* Note initializer is zero, so this works */
78pthread_rwlock_t _pthread_key_lock;
79unsigned _pthread_key_max;
80unsigned _pthread_key_sch;
81void (**_pthread_key_dest)(void *);
82
83
84#define pthread_cleanup_push(F, A)\
85{\
86 const _pthread_cleanup _pthread_cup = {(F), (A), pthread_self()->clean};\
87 _ReadWriteBarrier();\
88 pthread_self()->clean = (_pthread_cleanup *) &_pthread_cup;\
89 _ReadWriteBarrier()
90
91/* Note that if async cancelling is used, then there is a race here */
92#define pthread_cleanup_pop(E)\
93 (pthread_self()->clean = _pthread_cup.next, (E ? _pthread_cup.func(_pthread_cup.arg) : 0));}
94
95static void _pthread_once_cleanup(pthread_once_t *o)
96{
97 *o = 0;
98}
99
100int pthread_once(pthread_once_t *o, void (*func)(void))
101{
102 long state = *o;
103
104 _ReadWriteBarrier();
105
106 while (state != 1)
107 {
108 if (!state)
109 {
110 if (!_InterlockedCompareExchange(o, 2, 0))
111 {
112 /* Success */
113 pthread_cleanup_push((void(*)(void*))_pthread_once_cleanup, o);
114 func();
115 pthread_cleanup_pop(0);
116
117 /* Mark as done */
118 *o = 1;
119
120 return 0;
121 }
122 }
123
124 YieldProcessor();
125
126 _ReadWriteBarrier();
127
128 state = *o;
129 }
130
131 /* Done */
132 return 0;
133}
134
135static int _pthread_once_raw(pthread_once_t *o, void (*func)(void))
136{
137 long state = *o;
138
139 _ReadWriteBarrier();
140
141 while (state != 1)
142 {
143 if (!state)
144 {
145 if (!_InterlockedCompareExchange(o, 2, 0))
146 {
147 /* Success */
148 func();
149
150 /* Mark as done */
151 *o = 1;
152
153 return 0;
154 }
155 }
156
157 YieldProcessor();
158
159 _ReadWriteBarrier();
160
161 state = *o;
162 }
163
164 /* Done */
165 return 0;
166}
167
168int pthread_mutex_lock(pthread_mutex_t *m)
169{
170 EnterCriticalSection(m);
171 return 0;
172}
173
174int pthread_mutex_unlock(pthread_mutex_t *m)
175{
176 LeaveCriticalSection(m);
177 return 0;
178}
179
180int pthread_mutex_trylock(pthread_mutex_t *m)
181{
182 return TryEnterCriticalSection(m) ? 0 : EBUSY;
183}
184
185int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a)
186{
187 (void) a;
188 InitializeCriticalSection(m);
189
190 return 0;
191}
192
193int pthread_mutex_destroy(pthread_mutex_t *m)
194{
195 DeleteCriticalSection(m);
196 return 0;
197}
198
199int pthread_equal(pthread_t t1, pthread_t t2)
200{
201 return t1 == t2;
202}
203
204int pthread_rwlock_init(pthread_rwlock_t *l, pthread_rwlockattr_t *a)
205{
206 (void) a;
207 InitializeSRWLock(l);
208
209 return 0;
210}
211
212int pthread_rwlock_destroy(pthread_rwlock_t *l)
213{
214 (void) *l;
215 return 0;
216}
217
218int pthread_rwlock_rdlock(pthread_rwlock_t *l)
219{
220 pthread_testcancel();
221 AcquireSRWLockShared(l);
222
223 return 0;
224}
225
226int pthread_rwlock_wrlock(pthread_rwlock_t *l)
227{
228 pthread_testcancel();
229 AcquireSRWLockExclusive(l);
230
231 return 0;
232}
233
234int pthread_rwlock_unlock(pthread_rwlock_t *l)
235{
236 void *state = *(void **)l;
237
238 if (state == (void *)1)
239 {
240 /* Known to be an exclusive lock */
241 ReleaseSRWLockExclusive(l);
242 }
243 else
244 {
245 /* A shared unlock will work */
246 ReleaseSRWLockShared(l);
247 }
248
249 return 0;
250}
251
252int pthread_rwlock_tryrdlock(pthread_rwlock_t *l)
253{
254 /* Get the current state of the lock */
255 void *state = *(void **)l;
256
257 if (!state)
258 {
259 /* Unlocked to locked */
260 if (!_InterlockedCompareExchangePointer((void *volatile *)l, (void *)0x11, NULL)) return 0;
261 return EBUSY;
262 }
263
264 /* A single writer exists */
265 if (state == (void *)1) return EBUSY;
266
267 /* Multiple writers exist? */
268 if ((uintptr_t)state & 14) return EBUSY;
269
270 if (_InterlockedCompareExchangePointer((void *volatile *)l, (void *)((uintptr_t)state + 16), state) == state) return 0;
271
272 return EBUSY;
273}
274
275int pthread_rwlock_trywrlock(pthread_rwlock_t *l)
276{
277 /* Try to grab lock if it has no users */
278 if (!_InterlockedCompareExchangePointer((void *volatile *)l, (void *)1, NULL)) return 0;
279
280 return EBUSY;
281}
282
283void pthread_tls_init(void)
284{
285 _pthread_tls = TlsAlloc();
286
287 /* Cannot continue if out of indexes */
288 if (_pthread_tls == TLS_OUT_OF_INDEXES) abort();
289}
290
291static void _pthread_cleanup_dest(pthread_t t)
292{
293 unsigned i, j;
294
295 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
296 {
297 int flag = 0;
298
299 for (i = 0; i < t->keymax; i++)
300 {
301 void *val = t->keyval[i];
302
303 if (val)
304 {
305 pthread_rwlock_rdlock(&_pthread_key_lock);
306 if ((uintptr_t) _pthread_key_dest[i] > 1)
307 {
308 /* Call destructor */
309 t->keyval[i] = NULL;
310 _pthread_key_dest[i](val);
311 flag = 1;
312 }
313 pthread_rwlock_unlock(&_pthread_key_lock);
314 }
315 }
316
317 /* Nothing to do? */
318 if (!flag) return;
319 }
320}
321
322pthread_t pthread_self(void)
323{
324 pthread_t t;
325
326 _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
327
328 t = (struct _pthread_v*)TlsGetValue(_pthread_tls);
329 /* Main thread? */
330 if (!t)
331 {
332 t = (struct _pthread_v*)malloc(sizeof(struct _pthread_v));
333
334 /* If cannot initialize main thread, then the only thing we can do is abort */
335 if (!t) abort();
336
337 t->ret_arg = NULL;
338 t->func = NULL;
339 t->clean = NULL;
340 t->cancelled = 0;
341 t->p_state = PTHREAD_DEFAULT_ATTR;
342 t->keymax = 0;
343 t->keyval = NULL;
344 t->h = GetCurrentThread();
345
346 /* Save for later */
347 TlsSetValue(_pthread_tls, t);
348
349 if (setjmp(t->jb))
350 {
351 /* Make sure we free ourselves if we are detached */
352 if (!t->h) free(t);
353
354 /* Time to die */
355 _endthreadex(0);
356 }
357 }
358
359 return t;
360}
361
362static unsigned long long _pthread_time_in_ms(void)
363{
364 struct __timeb64 tb;
365
366 _ftime64(&tb);
367
368 return tb.time * 1000 + tb.millitm;
369}
370
371static unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts)
372{
373 unsigned long long t = ts->tv_sec * 1000;
374 t += ts->tv_nsec / 1000000;
375
376 return t;
377}
378
379static unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts)
380{
381 unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts);
382 unsigned long long t2 = _pthread_time_in_ms();
383
384 /* Prevent underflow */
385 if (t1 < t2) return 0;
386 return t1 - t2;
387}
388
389int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts)
390{
391 unsigned long long ct = _pthread_time_in_ms();
392 unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
393
394 pthread_testcancel();
395
396 /* Use a busy-loop */
397 while (1)
398 {
399 /* Try to grab lock */
400 if (!pthread_rwlock_tryrdlock(l)) return 0;
401
402 /* Get current time */
403 ct = _pthread_time_in_ms();
404
405 /* Have we waited long enough? */
406 if (ct > t) return ETIMEDOUT;
407 }
408}
409
410int pthread_rwlock_timedwrlock(pthread_rwlock_t *l, const struct timespec *ts)
411{
412 unsigned long long ct = _pthread_time_in_ms();
413 unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
414
415 pthread_testcancel();
416
417 /* Use a busy-loop */
418 while (1)
419 {
420 /* Try to grab lock */
421 if (!pthread_rwlock_trywrlock(l)) return 0;
422
423 /* Get current time */
424 ct = _pthread_time_in_ms();
425
426 /* Have we waited long enough? */
427 if (ct > t) return ETIMEDOUT;
428 }
429}
430
431int pthread_get_concurrency(int *val)
432{
433 *val = _pthread_concur;
434 return 0;
435}
436
437int pthread_set_concurrency(int val)
438{
439 _pthread_concur = val;
440 return 0;
441}
442
443int pthread_exit(void *res)
444{
445 pthread_t t = pthread_self();
446
447 t->ret_arg = res;
448
449 _pthread_cleanup_dest(t);
450
451 longjmp(t->jb, 1);
452}
453
454
455static void _pthread_invoke_cancel(void)
456{
457 _pthread_cleanup *pcup;
458
459 _InterlockedDecrement(&_pthread_cancelling);
460
461 /* Call cancel queue */
462 for (pcup = pthread_self()->clean; pcup; pcup = pcup->next)
463 {
464 pcup->func(pcup->arg);
465 }
466
467 pthread_exit(PTHREAD_CANCELED);
468}
469
470void pthread_testcancel(void)
471{
472 if (_pthread_cancelling)
473 {
474 pthread_t t = pthread_self();
475
476 if (t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE))
477 {
478 _pthread_invoke_cancel();
479 }
480 }
481}
482
483
484int pthread_cancel(pthread_t t)
485{
486#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP)
487 if (t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS)
488 {
489 /* Dangerous asynchronous cancelling */
490 CONTEXT ctxt;
491
492 /* Already done? */
493 if (t->cancelled) return ESRCH;
494
495 ctxt.ContextFlags = CONTEXT_CONTROL;
496
497 SuspendThread(t->h);
498 GetThreadContext(t->h, &ctxt);
499#ifdef _M_X64
500 ctxt.Rip = (uintptr_t) _pthread_invoke_cancel;
501#elif defined(_M_ARM64)
502 ctxt.Pc = (uintptr_t) _pthread_invoke_cancel;
503#else
504 ctxt.Eip = (uintptr_t) _pthread_invoke_cancel;
505#endif
506 SetThreadContext(t->h, &ctxt);
507
508 /* Also try deferred Cancelling */
509 t->cancelled = 1;
510
511 /* Notify everyone to look */
512 _InterlockedIncrement(&_pthread_cancelling);
513
514 ResumeThread(t->h);
515 }
516 else
517#endif
518 {
519 /* Safe deferred Cancelling */
520 t->cancelled = 1;
521
522 /* Notify everyone to look */
523 _InterlockedIncrement(&_pthread_cancelling);
524 }
525
526 return 0;
527}
528
529static unsigned _pthread_get_state(pthread_attr_t *attr, unsigned flag)
530{
531 return attr->p_state & flag;
532}
533
534static int _pthread_set_state(pthread_attr_t *attr, unsigned flag, unsigned val)
535{
536 if (~flag & val) return EINVAL;
537 attr->p_state &= ~flag;
538 attr->p_state |= val;
539
540 return 0;
541}
542
543int pthread_attr_init(pthread_attr_t *attr)
544{
545 attr->p_state = PTHREAD_DEFAULT_ATTR;
546 attr->stack = NULL;
547 attr->s_size = 0;
548 return 0;
549}
550
551int pthread_attr_destroy(pthread_attr_t *attr)
552{
553 /* No need to do anything */
554 return 0;
555}
556
557
558int pthread_attr_setdetachstate(pthread_attr_t *a, int flag)
559{
560 return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag);
561}
562
563int pthread_attr_getdetachstate(pthread_attr_t *a, int *flag)
564{
565 *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED);
566 return 0;
567}
568
569int pthread_attr_setinheritsched(pthread_attr_t *a, int flag)
570{
571 return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag);
572}
573
574int pthread_attr_getinheritsched(pthread_attr_t *a, int *flag)
575{
576 *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED);
577 return 0;
578}
579
580int pthread_attr_setscope(pthread_attr_t *a, int flag)
581{
582 return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag);
583}
584
585int pthread_attr_getscope(pthread_attr_t *a, int *flag)
586{
587 *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM);
588 return 0;
589}
590
591int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stack)
592{
593 *stack = attr->stack;
594 return 0;
595}
596
597int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack)
598{
599 attr->stack = stack;
600 return 0;
601}
602
603int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *size)
604{
605 *size = attr->s_size;
606 return 0;
607}
608
609int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size)
610{
611 attr->s_size = size;
612 return 0;
613}
614
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
621
622
623int pthread_setcancelstate(int state, int *oldstate)
624{
625 pthread_t t = pthread_self();
626
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;
630 t->p_state |= state;
631
632 return 0;
633}
634
635int pthread_setcanceltype(int type, int *oldtype)
636{
637 pthread_t t = pthread_self();
638
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;
642 t->p_state |= type;
643
644 return 0;
645}
646
647unsigned __stdcall pthread_create_wrapper(void *args)
648{
649 struct _pthread_v *tv = (struct _pthread_v*)args;
650
651 _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
652
653 TlsSetValue(_pthread_tls, tv);
654
655 if (!setjmp(tv->jb))
656 {
657 /* Call function and save return value */
658 tv->ret_arg = tv->func(tv->ret_arg);
659
660 /* Clean up destructors */
661 _pthread_cleanup_dest(tv);
662 }
663
664 /* If we exit too early, then we can race with create */
665 while (tv->h == (HANDLE) -1)
666 {
667 YieldProcessor();
668 _ReadWriteBarrier();
669 }
670
671 /* Make sure we free ourselves if we are detached */
672 if (!tv->h) free(tv);
673
674 return 0;
675}
676
677int pthread_create(pthread_t *th, pthread_attr_t *attr, void *(* func)(void *), void *arg)
678{
679 struct _pthread_v *tv = (struct _pthread_v*)malloc(sizeof(struct _pthread_v));
680 unsigned ssize = 0;
681
682 if (!tv) return 1;
683
684 *th = tv;
685
686 /* Save data in pthread_t */
687 tv->ret_arg = arg;
688 tv->func = func;
689 tv->clean = NULL;
690 tv->cancelled = 0;
691 tv->p_state = PTHREAD_DEFAULT_ATTR;
692 tv->keymax = 0;
693 tv->keyval = NULL;
694 tv->h = (HANDLE) -1;
695
696 if (attr)
697 {
698 tv->p_state = attr->p_state;
699 ssize = (unsigned) attr->s_size;
700 }
701
702 /* Make sure tv->h has value of -1 */
703 _ReadWriteBarrier();
704
705 tv->h = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0, NULL);
706
707 /* Failed */
708 if (!tv->h) return 1;
709
710 if (tv->p_state & PTHREAD_CREATE_DETACHED)
711 {
712 CloseHandle(tv->h);
713 _ReadWriteBarrier();
714 tv->h = 0;
715 }
716
717 return 0;
718}
719
720int pthread_join(pthread_t t, void **res)
721{
722 struct _pthread_v *tv = t;
723
724 pthread_testcancel();
725
726 WaitForSingleObject(tv->h, INFINITE);
727 CloseHandle(tv->h);
728
729 /* Obtain return value */
730 if (res) *res = tv->ret_arg;
731
732 free(tv);
733
734 return 0;
735}
736
737int pthread_detach(pthread_t t)
738{
739 struct _pthread_v *tv = t;
740
741 /*
742 * This can't race with thread exit because
743 * our call would be undefined if called on a dead thread.
744 */
745
746 CloseHandle(tv->h);
747 _ReadWriteBarrier();
748 tv->h = 0;
749
750 return 0;
751}
752
753int pthread_mutexattr_init(pthread_mutexattr_t *a)
754{
755 *a = 0;
756 return 0;
757}
758
759int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
760{
761 (void) a;
762 return 0;
763}
764
765int pthread_mutexattr_gettype(pthread_mutexattr_t *a, int *type)
766{
767 *type = *a & 3;
768
769 return 0;
770}
771
772int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
773{
774 if ((unsigned) type > 3) return EINVAL;
775 *a &= ~3;
776 *a |= type;
777
778 return 0;
779}
780
781int pthread_mutexattr_getpshared(pthread_mutexattr_t *a, int *type)
782{
783 *type = *a & 4;
784
785 return 0;
786}
787
788int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type)
789{
790 if ((type & 4) != type) return EINVAL;
791
792 *a &= ~4;
793 *a |= type;
794
795 return 0;
796}
797
798int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a, int *type)
799{
800 *type = *a & (8 + 16);
801
802 return 0;
803}
804
805int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type)
806{
807 if ((type & (8 + 16)) != 8 + 16) return EINVAL;
808
809 *a &= ~(8 + 16);
810 *a |= type;
811
812 return 0;
813}
814
815int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a, int * prio)
816{
817 *prio = *a / PTHREAD_PRIO_MULT;
818 return 0;
819}
820
821int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio)
822{
823 *a &= (PTHREAD_PRIO_MULT - 1);
824 *a += prio * PTHREAD_PRIO_MULT;
825
826 return 0;
827}
828
829int pthread_mutex_timedlock(pthread_mutex_t *m, struct timespec *ts)
830{
831 unsigned long long t, ct;
832
833 struct _pthread_crit_t
834 {
835 void *debug;
836 LONG count;
837 LONG r_count;
838 HANDLE owner;
839 HANDLE sem;
840 ULONG_PTR spin;
841 };
842
843 /* Try to lock it without waiting */
844 if (!pthread_mutex_trylock(m)) return 0;
845
846 ct = _pthread_time_in_ms();
847 t = _pthread_time_in_ms_from_timespec(ts);
848
849 while (1)
850 {
851 /* Have we waited long enough? */
852 if (ct > t) return ETIMEDOUT;
853
854 /* Wait on semaphore within critical section */
855 WaitForSingleObject(((struct _pthread_crit_t *)m)->sem, (DWORD)(t - ct));
856
857 /* Try to grab lock */
858 if (!pthread_mutex_trylock(m)) return 0;
859
860 /* Get current time */
861 ct = _pthread_time_in_ms();
862 }
863}
864
865#define _PTHREAD_BARRIER_FLAG (1<<30)
866
867int pthread_barrier_destroy(pthread_barrier_t *b)
868{
869 EnterCriticalSection(&b->m);
870
871 while (b->total > _PTHREAD_BARRIER_FLAG)
872 {
873 /* Wait until everyone exits the barrier */
874 SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
875 }
876
877 LeaveCriticalSection(&b->m);
878
879 DeleteCriticalSection(&b->m);
880
881 return 0;
882}
883
884int pthread_barrier_init(pthread_barrier_t *b, void *attr, int count)
885{
886 /* Ignore attr */
887 (void) attr;
888
889 b->count = count;
890 b->total = 0;
891
892 InitializeCriticalSection(&b->m);
893 InitializeConditionVariable(&b->cv);
894
895 return 0;
896}
897
898int pthread_barrier_wait(pthread_barrier_t *b)
899{
900 EnterCriticalSection(&b->m);
901
902 while (b->total > _PTHREAD_BARRIER_FLAG)
903 {
904 /* Wait until everyone exits the barrier */
905 SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
906 }
907
908 /* Are we the first to enter? */
909 if (b->total == _PTHREAD_BARRIER_FLAG) b->total = 0;
910
911 b->total++;
912
913 if (b->total == b->count)
914 {
915 b->total += _PTHREAD_BARRIER_FLAG - 1;
916 WakeAllConditionVariable(&b->cv);
917
918 LeaveCriticalSection(&b->m);
919
920 return 1;
921 }
922 else
923 {
924 while (b->total < _PTHREAD_BARRIER_FLAG)
925 {
926 /* Wait until enough threads enter the barrier */
927 SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
928 }
929
930 b->total--;
931
932 /* Get entering threads to wake up */
933 if (b->total == _PTHREAD_BARRIER_FLAG) WakeAllConditionVariable(&b->cv);
934
935 LeaveCriticalSection(&b->m);
936
937 return 0;
938 }
939}
940
941int pthread_barrierattr_init(void **attr)
942{
943 *attr = NULL;
944 return 0;
945}
946
947int pthread_barrierattr_destroy(void **attr)
948{
949 /* Ignore attr */
950 (void) attr;
951
952 return 0;
953}
954
955int pthread_barrierattr_setpshared(void **attr, int s)
956{
957 *attr = (void *) s;
958 return 0;
959}
960
961int pthread_barrierattr_getpshared(void **attr, int *s)
962{
963 *s = (int) (size_t) *attr;
964
965 return 0;
966}
967
968int pthread_key_create(pthread_key_t *key, void (* dest)(void *))
969{
970 unsigned i;
971 unsigned nmax;
972 void (**d)(void *);
973
974 if (!key) return EINVAL;
975
976 pthread_rwlock_wrlock(&_pthread_key_lock);
977
978 for (i = _pthread_key_sch; i < _pthread_key_max; i++)
979 {
980 if (!_pthread_key_dest[i])
981 {
982 *key = i;
983 if (dest)
984 {
985 _pthread_key_dest[i] = dest;
986 }
987 else
988 {
989 _pthread_key_dest[i] = (void(*)(void *))1;
990 }
991 pthread_rwlock_unlock(&_pthread_key_lock);
992
993 return 0;
994 }
995 }
996
997 for (i = 0; i < _pthread_key_sch; i++)
998 {
999 if (!_pthread_key_dest[i])
1000 {
1001 *key = i;
1002 if (dest)
1003 {
1004 _pthread_key_dest[i] = dest;
1005 }
1006 else
1007 {
1008 _pthread_key_dest[i] = (void(*)(void *))1;
1009 }
1010 pthread_rwlock_unlock(&_pthread_key_lock);
1011
1012 return 0;
1013 }
1014 }
1015
1016 if (!_pthread_key_max) _pthread_key_max = 1;
1017 if (_pthread_key_max == PTHREAD_KEYS_MAX)
1018 {
1019 pthread_rwlock_unlock(&_pthread_key_lock);
1020
1021 return ENOMEM;
1022 }
1023
1024 nmax = _pthread_key_max * 2;
1025 if (nmax > PTHREAD_KEYS_MAX) nmax = PTHREAD_KEYS_MAX;
1026
1027 /* No spare room anywhere */
1028 d = (void (**)(void*))realloc(_pthread_key_dest, nmax * sizeof(*d));
1029 if (!d)
1030 {
1031 pthread_rwlock_unlock(&_pthread_key_lock);
1032
1033 return ENOMEM;
1034 }
1035
1036 /* Clear new region */
1037 memset((void *) &d[_pthread_key_max], 0, (nmax-_pthread_key_max)*sizeof(void *));
1038
1039 /* Use new region */
1040 _pthread_key_dest = d;
1041 _pthread_key_sch = _pthread_key_max + 1;
1042 *key = _pthread_key_max;
1043 _pthread_key_max = nmax;
1044
1045 if (dest)
1046 {
1047 _pthread_key_dest[*key] = dest;
1048 }
1049 else
1050 {
1051 _pthread_key_dest[*key] = (void(*)(void *))1;
1052 }
1053
1054 pthread_rwlock_unlock(&_pthread_key_lock);
1055
1056 return 0;
1057}
1058
1059int pthread_key_delete(pthread_key_t key)
1060{
1061 if (key > _pthread_key_max) return EINVAL;
1062 if (!_pthread_key_dest) return EINVAL;
1063
1064 pthread_rwlock_wrlock(&_pthread_key_lock);
1065 _pthread_key_dest[key] = NULL;
1066
1067 /* Start next search from our location */
1068 if (_pthread_key_sch > key) _pthread_key_sch = key;
1069
1070 pthread_rwlock_unlock(&_pthread_key_lock);
1071
1072 return 0;
1073}
1074
1075void *pthread_getspecific(pthread_key_t key)
1076{
1077 pthread_t t = pthread_self();
1078
1079 if (key >= t->keymax) return NULL;
1080
1081 return t->keyval[key];
1082
1083}
1084
1085int pthread_setspecific(pthread_key_t key, const void *value)
1086{
1087 pthread_t t = pthread_self();
1088
1089 if (key > t->keymax)
1090 {
1091 int keymax = (key + 1) * 2;
1092 void **kv = (void**)realloc(t->keyval, keymax * sizeof(void *));
1093
1094 if (!kv) return ENOMEM;
1095
1096 /* Clear new region */
1097 memset(&kv[t->keymax], 0, (keymax - t->keymax)*sizeof(void*));
1098
1099 t->keyval = kv;
1100 t->keymax = keymax;
1101 }
1102
1103 t->keyval[key] = (void *) value;
1104
1105 return 0;
1106}
1107
1108
1109int pthread_spin_init(pthread_spinlock_t *l, int pshared)
1110{
1111 (void) pshared;
1112
1113 *l = 0;
1114 return 0;
1115}
1116
1117int pthread_spin_destroy(pthread_spinlock_t *l)
1118{
1119 (void) l;
1120 return 0;
1121}
1122
1123/* No-fair spinlock due to lack of knowledge of thread number */
1124int pthread_spin_lock(pthread_spinlock_t *l)
1125{
1126 while (_InterlockedExchange(l, EBUSY))
1127 {
1128 /* Don't lock the bus whilst waiting */
1129 while (*l)
1130 {
1131 YieldProcessor();
1132
1133 /* Compiler barrier. Prevent caching of *l */
1134 _ReadWriteBarrier();
1135 }
1136 }
1137
1138 return 0;
1139}
1140
1141int pthread_spin_trylock(pthread_spinlock_t *l)
1142{
1143 return _InterlockedExchange(l, EBUSY);
1144}
1145
1146int pthread_spin_unlock(pthread_spinlock_t *l)
1147{
1148 /* Compiler barrier. The store below acts with release symmantics */
1149 _ReadWriteBarrier();
1150
1151 *l = 0;
1152
1153 return 0;
1154}
1155
1156int pthread_cond_init(pthread_cond_t *c, pthread_condattr_t *a)
1157{
1158 (void) a;
1159
1160 InitializeConditionVariable(c);
1161 return 0;
1162}
1163
1164int pthread_cond_signal(pthread_cond_t *c)
1165{
1166 WakeConditionVariable(c);
1167 return 0;
1168}
1169
1170int pthread_cond_broadcast(pthread_cond_t *c)
1171{
1172 WakeAllConditionVariable(c);
1173 return 0;
1174}
1175
1176int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
1177{
1178 pthread_testcancel();
1179 SleepConditionVariableCS(c, m, INFINITE);
1180 return 0;
1181}
1182
1183int pthread_cond_destroy(pthread_cond_t *c)
1184{
1185 (void) c;
1186 return 0;
1187}
1188
1189int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, struct timespec *t)
1190{
1191 unsigned long long tm = _pthread_rel_time_in_ms(t);
1192
1193 pthread_testcancel();
1194
1195 if (!SleepConditionVariableCS(c, m, (DWORD)tm)) return ETIMEDOUT;
1196
1197 /* We can have a spurious wakeup after the timeout */
1198 if (!_pthread_rel_time_in_ms(t)) return ETIMEDOUT;
1199
1200 return 0;
1201}
1202
1203int pthread_condattr_destroy(pthread_condattr_t *a)
1204{
1205 (void) a;
1206 return 0;
1207}
1208
1209int pthread_condattr_init(pthread_condattr_t *a)
1210{
1211 *a = 0;
1212 return 0;
1213}
1214
1215int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
1216{
1217 *s = *a;
1218 return 0;
1219}
1220
1221int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
1222{
1223 *a = s;
1224 return 0;
1225}
1226
1227int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a)
1228{
1229 (void) a;
1230 return 0;
1231}
1232
1233int pthread_rwlockattr_init(pthread_rwlockattr_t *a)
1234{
1235 *a = 0;
1236 return 0;
1237}
1238
1239int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s)
1240{
1241 *s = *a;
1242 return 0;
1243}
1244
1245int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s)
1246{
1247 *a = s;
1248 return 0;
1249}