|
@@ -0,0 +1,1605 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * Posix Threads library for Microsoft Windows
|
|
|
|
|
+ *
|
|
|
|
|
+ * Use at own risk, there is no implied warranty to this code.
|
|
|
|
|
+ * It uses undocumented features of Microsoft Windows that can change
|
|
|
|
|
+ * at any time in the future.
|
|
|
|
|
+ *
|
|
|
|
|
+ * (C) 2010 Lockless Inc.
|
|
|
|
|
+ * All rights reserved.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
|
+ * are permitted provided that the following conditions are met:
|
|
|
|
|
+ *
|
|
|
|
|
+ *
|
|
|
|
|
+ * * Redistributions of source code must retain the above copyright notice,
|
|
|
|
|
+ * this list of conditions and the following disclaimer.
|
|
|
|
|
+ * * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
|
+ * this list of conditions and the following disclaimer in the documentation
|
|
|
|
|
+ * and/or other materials provided with the distribution.
|
|
|
|
|
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
|
|
|
|
|
+ * used to endorse or promote products derived from this software without
|
|
|
|
|
+ * specific prior written permission.
|
|
|
|
|
+ *
|
|
|
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
|
|
|
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
|
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
|
|
|
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
|
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
|
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
|
|
|
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
|
|
|
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
|
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * You may want to use the MingW64 winpthreads library instead.
|
|
|
|
|
+ * It is based on this, but adds error checking.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Version 1.0.1 Released 2 Feb 2012
|
|
|
|
|
+ * Fixes pthread_barrier_destroy() to wait for threads to exit the barrier.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+#ifndef WIN_PTHREADS
|
|
|
|
|
+#define WIN_PTHREADS
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#include <windows.h>
|
|
|
|
|
+#include <setjmp.h>
|
|
|
|
|
+#include <errno.h>
|
|
|
|
|
+#include <sys/timeb.h>
|
|
|
|
|
+
|
|
|
|
|
+#define ETIMEDOUT 110
|
|
|
|
|
+#define ENOTSUP 134
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_CANCEL_DISABLE 0
|
|
|
|
|
+#define PTHREAD_CANCEL_ENABLE 0x01
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_CANCEL_DEFERRED 0
|
|
|
|
|
+#define PTHREAD_CANCEL_ASYNCHRONOUS 0x02
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_CREATE_JOINABLE 0
|
|
|
|
|
+#define PTHREAD_CREATE_DETACHED 0x04
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_EXPLICT_SCHED 0
|
|
|
|
|
+#define PTHREAD_INHERIT_SCHED 0x08
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_SCOPE_PROCESS 0
|
|
|
|
|
+#define PTHREAD_SCOPE_SYSTEM 0x10
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_DEFAULT_ATTR (PTHREAD_CANCEL_ENABLE)
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_CANCELED ((void *) 0xDEADBEEF)
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_ONCE_INIT 0
|
|
|
|
|
+#define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0}
|
|
|
|
|
+#define PTHREAD_RWLOCK_INITIALIZER {0}
|
|
|
|
|
+#define PTHREAD_COND_INITIALIZER {0}
|
|
|
|
|
+#define PTHREAD_BARRIER_INITIALIZER \
|
|
|
|
|
+ {0,0,PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER}
|
|
|
|
|
+#define PTHREAD_SPINLOCK_INITIALIZER 0
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_DESTRUCTOR_ITERATIONS 256
|
|
|
|
|
+#define PTHREAD_KEYS_MAX (1<<20)
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_MUTEX_NORMAL 0
|
|
|
|
|
+#define PTHREAD_MUTEX_ERRORCHECK 1
|
|
|
|
|
+#define PTHREAD_MUTEX_RECURSIVE 2
|
|
|
|
|
+#define PTHREAD_MUTEX_DEFAULT 3
|
|
|
|
|
+#define PTHREAD_MUTEX_SHARED 4
|
|
|
|
|
+#define PTHREAD_MUTEX_PRIVATE 0
|
|
|
|
|
+#define PTHREAD_PRIO_NONE 0
|
|
|
|
|
+#define PTHREAD_PRIO_INHERIT 8
|
|
|
|
|
+#define PTHREAD_PRIO_PROTECT 16
|
|
|
|
|
+#define PTHREAD_PRIO_MULT 32
|
|
|
|
|
+#define PTHREAD_PROCESS_SHARED 0
|
|
|
|
|
+#define PTHREAD_PROCESS_PRIVATE 1
|
|
|
|
|
+
|
|
|
|
|
+#define PTHREAD_BARRIER_SERIAL_THREAD 1
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* Windows doesn't have this, so declare it ourselves. */
|
|
|
|
|
+struct timespec
|
|
|
|
|
+{
|
|
|
|
|
+ /* long long in windows is the same as long in unix for 64bit */
|
|
|
|
|
+ long long tv_sec;
|
|
|
|
|
+ long long tv_nsec;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+typedef struct _pthread_cleanup _pthread_cleanup;
|
|
|
|
|
+struct _pthread_cleanup
|
|
|
|
|
+{
|
|
|
|
|
+ void (*func)(void *);
|
|
|
|
|
+ void *arg;
|
|
|
|
|
+ _pthread_cleanup *next;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+struct _pthread_v
|
|
|
|
|
+{
|
|
|
|
|
+ void *ret_arg;
|
|
|
|
|
+ void *(* func)(void *);
|
|
|
|
|
+ _pthread_cleanup *clean;
|
|
|
|
|
+ HANDLE h;
|
|
|
|
|
+ int cancelled;
|
|
|
|
|
+ unsigned p_state;
|
|
|
|
|
+ int keymax;
|
|
|
|
|
+ void **keyval;
|
|
|
|
|
+
|
|
|
|
|
+ jmp_buf jb;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+typedef struct _pthread_v *pthread_t;
|
|
|
|
|
+
|
|
|
|
|
+typedef struct pthread_barrier_t pthread_barrier_t;
|
|
|
|
|
+struct pthread_barrier_t
|
|
|
|
|
+{
|
|
|
|
|
+ int count;
|
|
|
|
|
+ int total;
|
|
|
|
|
+ CRITICAL_SECTION m;
|
|
|
|
|
+ CONDITION_VARIABLE cv;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+typedef struct pthread_attr_t pthread_attr_t;
|
|
|
|
|
+struct pthread_attr_t
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned p_state;
|
|
|
|
|
+ void *stack;
|
|
|
|
|
+ size_t s_size;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+typedef long pthread_once_t;
|
|
|
|
|
+typedef unsigned pthread_mutexattr_t;
|
|
|
|
|
+typedef SRWLOCK pthread_rwlock_t;
|
|
|
|
|
+typedef CRITICAL_SECTION pthread_mutex_t;
|
|
|
|
|
+typedef unsigned pthread_key_t;
|
|
|
|
|
+typedef void *pthread_barrierattr_t;
|
|
|
|
|
+typedef long pthread_spinlock_t;
|
|
|
|
|
+typedef int pthread_condattr_t;
|
|
|
|
|
+typedef CONDITION_VARIABLE pthread_cond_t;
|
|
|
|
|
+typedef int pthread_rwlockattr_t;
|
|
|
|
|
+
|
|
|
|
|
+volatile long _pthread_cancelling;
|
|
|
|
|
+
|
|
|
|
|
+int _pthread_concur;
|
|
|
|
|
+
|
|
|
|
|
+/* Will default to zero as needed */
|
|
|
|
|
+pthread_once_t _pthread_tls_once;
|
|
|
|
|
+DWORD _pthread_tls;
|
|
|
|
|
+
|
|
|
|
|
+/* Note initializer is zero, so this works */
|
|
|
|
|
+pthread_rwlock_t _pthread_key_lock;
|
|
|
|
|
+long _pthread_key_max;
|
|
|
|
|
+long _pthread_key_sch;
|
|
|
|
|
+void (**_pthread_key_dest)(void *);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#define pthread_cleanup_push(F, A)\
|
|
|
|
|
+{\
|
|
|
|
|
+ const _pthread_cleanup _pthread_cup = {(F), (A), pthread_self()->clean};\
|
|
|
|
|
+ _ReadWriteBarrier();\
|
|
|
|
|
+ pthread_self()->clean = (_pthread_cleanup *) &_pthread_cup;\
|
|
|
|
|
+ _ReadWriteBarrier()
|
|
|
|
|
+
|
|
|
|
|
+/* Note that if async cancelling is used, then there is a race here */
|
|
|
|
|
+#define pthread_cleanup_pop(E)\
|
|
|
|
|
+ (pthread_self()->clean = _pthread_cup.next, (E?_pthread_cup.func(_pthread_cup.arg):0));}
|
|
|
|
|
+
|
|
|
|
|
+static void _pthread_once_cleanup(pthread_once_t *o)
|
|
|
|
|
+{
|
|
|
|
|
+ *o = 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static pthread_t pthread_self(void);
|
|
|
|
|
+static int pthread_once(pthread_once_t *o, void (*func)(void))
|
|
|
|
|
+{
|
|
|
|
|
+ long state = *o;
|
|
|
|
|
+
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+
|
|
|
|
|
+ while (state != 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!state)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!_InterlockedCompareExchange(o, 2, 0))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Success */
|
|
|
|
|
+ pthread_cleanup_push(_pthread_once_cleanup, o);
|
|
|
|
|
+ func();
|
|
|
|
|
+ pthread_cleanup_pop(0);
|
|
|
|
|
+
|
|
|
|
|
+ /* Mark as done */
|
|
|
|
|
+ *o = 1;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ YieldProcessor();
|
|
|
|
|
+
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+
|
|
|
|
|
+ state = *o;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Done */
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int _pthread_once_raw(pthread_once_t *o, void (*func)(void))
|
|
|
|
|
+{
|
|
|
|
|
+ long state = *o;
|
|
|
|
|
+
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+
|
|
|
|
|
+ while (state != 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!state)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!_InterlockedCompareExchange(o, 2, 0))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Success */
|
|
|
|
|
+ func();
|
|
|
|
|
+
|
|
|
|
|
+ /* Mark as done */
|
|
|
|
|
+ *o = 1;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ YieldProcessor();
|
|
|
|
|
+
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+
|
|
|
|
|
+ state = *o;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Done */
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutex_lock(pthread_mutex_t *m)
|
|
|
|
|
+{
|
|
|
|
|
+ EnterCriticalSection(m);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutex_unlock(pthread_mutex_t *m)
|
|
|
|
|
+{
|
|
|
|
|
+ LeaveCriticalSection(m);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutex_trylock(pthread_mutex_t *m)
|
|
|
|
|
+{
|
|
|
|
|
+ return TryEnterCriticalSection(m) ? 0 : EBUSY;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) a;
|
|
|
|
|
+ InitializeCriticalSection(m);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutex_destroy(pthread_mutex_t *m)
|
|
|
|
|
+{
|
|
|
|
|
+ DeleteCriticalSection(m);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define pthread_mutex_getprioceiling(M, P) ENOTSUP
|
|
|
|
|
+#define pthread_mutex_setprioceiling(M, P) ENOTSUP
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_equal(pthread_t t1, pthread_t t2)
|
|
|
|
|
+{
|
|
|
|
|
+ return t1 == t2;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void pthread_testcancel(void);
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_init(pthread_rwlock_t *l, pthread_rwlockattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) a;
|
|
|
|
|
+ InitializeSRWLock(l);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_destroy(pthread_rwlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) *l;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_rdlock(pthread_rwlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+ AcquireSRWLockShared(l);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_wrlock(pthread_rwlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+ AcquireSRWLockExclusive(l);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void pthread_tls_init(void)
|
|
|
|
|
+{
|
|
|
|
|
+ _pthread_tls = TlsAlloc();
|
|
|
|
|
+
|
|
|
|
|
+ /* Cannot continue if out of indexes */
|
|
|
|
|
+ if (_pthread_tls == TLS_OUT_OF_INDEXES) abort();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void _pthread_cleanup_dest(pthread_t t)
|
|
|
|
|
+{
|
|
|
|
|
+ int i, j;
|
|
|
|
|
+
|
|
|
|
|
+ for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
|
|
|
|
|
+ {
|
|
|
|
|
+ int flag = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < t->keymax; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ void *val = t->keyval[i];
|
|
|
|
|
+
|
|
|
|
|
+ if (val)
|
|
|
|
|
+ {
|
|
|
|
|
+ pthread_rwlock_rdlock(&_pthread_key_lock);
|
|
|
|
|
+ if ((uintptr_t) _pthread_key_dest[i] > 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Call destructor */
|
|
|
|
|
+ t->keyval[i] = NULL;
|
|
|
|
|
+ _pthread_key_dest[i](val);
|
|
|
|
|
+ flag = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Nothing to do? */
|
|
|
|
|
+ if (!flag) return;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static pthread_t pthread_self(void)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_t t;
|
|
|
|
|
+
|
|
|
|
|
+ _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
|
|
|
|
|
+
|
|
|
|
|
+ t = TlsGetValue(_pthread_tls);
|
|
|
|
|
+
|
|
|
|
|
+ /* Main thread? */
|
|
|
|
|
+ if (!t)
|
|
|
|
|
+ {
|
|
|
|
|
+ t = malloc(sizeof(struct _pthread_v));
|
|
|
|
|
+
|
|
|
|
|
+ /* If cannot initialize main thread, then the only thing we can do is abort */
|
|
|
|
|
+ if (!t) abort();
|
|
|
|
|
+
|
|
|
|
|
+ t->ret_arg = NULL;
|
|
|
|
|
+ t->func = NULL;
|
|
|
|
|
+ t->clean = NULL;
|
|
|
|
|
+ t->cancelled = 0;
|
|
|
|
|
+ t->p_state = PTHREAD_DEFAULT_ATTR;
|
|
|
|
|
+ t->keymax = 0;
|
|
|
|
|
+ t->keyval = NULL;
|
|
|
|
|
+ t->h = GetCurrentThread();
|
|
|
|
|
+
|
|
|
|
|
+ /* Save for later */
|
|
|
|
|
+ TlsSetValue(_pthread_tls, t);
|
|
|
|
|
+
|
|
|
|
|
+ if (setjmp(t->jb))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Make sure we free ourselves if we are detached */
|
|
|
|
|
+ if (!t->h) free(t);
|
|
|
|
|
+
|
|
|
|
|
+ /* Time to die */
|
|
|
|
|
+ _endthreadex(0);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return t;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_unlock(pthread_rwlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ void *state = *(void **)l;
|
|
|
|
|
+
|
|
|
|
|
+ if (state == (void *) 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Known to be an exclusive lock */
|
|
|
|
|
+ ReleaseSRWLockExclusive(l);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* A shared unlock will work */
|
|
|
|
|
+ ReleaseSRWLockShared(l);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_tryrdlock(pthread_rwlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ /* Get the current state of the lock */
|
|
|
|
|
+ void *state = *(void **) l;
|
|
|
|
|
+
|
|
|
|
|
+ if (!state)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Unlocked to locked */
|
|
|
|
|
+ if (!_InterlockedCompareExchangePointer((void *) l, (void *)0x11, NULL)) return 0;
|
|
|
|
|
+ return EBUSY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* A single writer exists */
|
|
|
|
|
+ if (state == (void *) 1) return EBUSY;
|
|
|
|
|
+
|
|
|
|
|
+ /* Multiple writers exist? */
|
|
|
|
|
+ if ((uintptr_t) state & 14) return EBUSY;
|
|
|
|
|
+
|
|
|
|
|
+ if (_InterlockedCompareExchangePointer((void *) l, (void *) ((uintptr_t)state + 16), state) == state) return 0;
|
|
|
|
|
+
|
|
|
|
|
+ return EBUSY;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_trywrlock(pthread_rwlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ /* Try to grab lock if it has no users */
|
|
|
|
|
+ if (!_InterlockedCompareExchangePointer((void *) l, (void *)1, NULL)) return 0;
|
|
|
|
|
+
|
|
|
|
|
+ return EBUSY;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static unsigned long long _pthread_time_in_ms(void)
|
|
|
|
|
+{
|
|
|
|
|
+ struct __timeb64 tb;
|
|
|
|
|
+
|
|
|
|
|
+ _ftime64(&tb);
|
|
|
|
|
+
|
|
|
|
|
+ return tb.time * 1000 + tb.millitm;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long long t = ts->tv_sec * 1000;
|
|
|
|
|
+ t += ts->tv_nsec / 1000000;
|
|
|
|
|
+
|
|
|
|
|
+ return t;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts);
|
|
|
|
|
+ unsigned long long t2 = _pthread_time_in_ms();
|
|
|
|
|
+
|
|
|
|
|
+ /* Prevent underflow */
|
|
|
|
|
+ if (t1 < t2) return 0;
|
|
|
|
|
+ return t1 - t2;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long long ct = _pthread_time_in_ms();
|
|
|
|
|
+ unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
|
|
|
|
|
+
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+
|
|
|
|
|
+ /* Use a busy-loop */
|
|
|
|
|
+ while (1)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Try to grab lock */
|
|
|
|
|
+ if (!pthread_rwlock_tryrdlock(l)) return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* Get current time */
|
|
|
|
|
+ ct = _pthread_time_in_ms();
|
|
|
|
|
+
|
|
|
|
|
+ /* Have we waited long enough? */
|
|
|
|
|
+ if (ct > t) return ETIMEDOUT;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlock_timedwrlock(pthread_rwlock_t *l, const struct timespec *ts)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long long ct = _pthread_time_in_ms();
|
|
|
|
|
+ unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
|
|
|
|
|
+
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+
|
|
|
|
|
+ /* Use a busy-loop */
|
|
|
|
|
+ while (1)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Try to grab lock */
|
|
|
|
|
+ if (!pthread_rwlock_trywrlock(l)) return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* Get current time */
|
|
|
|
|
+ ct = _pthread_time_in_ms();
|
|
|
|
|
+
|
|
|
|
|
+ /* Have we waited long enough? */
|
|
|
|
|
+ if (ct > t) return ETIMEDOUT;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_get_concurrency(int *val)
|
|
|
|
|
+{
|
|
|
|
|
+ *val = _pthread_concur;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_set_concurrency(int val)
|
|
|
|
|
+{
|
|
|
|
|
+ _pthread_concur = val;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define pthread_getschedparam(T, P, S) ENOTSUP
|
|
|
|
|
+#define pthread_setschedparam(T, P, S) ENOTSUP
|
|
|
|
|
+#define pthread_getcpuclockid(T, C) ENOTSUP
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_exit(void *res)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_t t = pthread_self();
|
|
|
|
|
+
|
|
|
|
|
+ t->ret_arg = res;
|
|
|
|
|
+
|
|
|
|
|
+ _pthread_cleanup_dest(t);
|
|
|
|
|
+
|
|
|
|
|
+ longjmp(t->jb, 1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+static void _pthread_invoke_cancel(void)
|
|
|
|
|
+{
|
|
|
|
|
+ _pthread_cleanup *pcup;
|
|
|
|
|
+
|
|
|
|
|
+ _InterlockedDecrement(&_pthread_cancelling);
|
|
|
|
|
+
|
|
|
|
|
+ /* Call cancel queue */
|
|
|
|
|
+ for (pcup = pthread_self()->clean; pcup; pcup = pcup->next)
|
|
|
|
|
+ {
|
|
|
|
|
+ pcup->func(pcup->arg);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pthread_exit(PTHREAD_CANCELED);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void pthread_testcancel(void)
|
|
|
|
|
+{
|
|
|
|
|
+ if (_pthread_cancelling)
|
|
|
|
|
+ {
|
|
|
|
|
+ pthread_t t = pthread_self();
|
|
|
|
|
+
|
|
|
|
|
+ if (t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE))
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_invoke_cancel();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cancel(pthread_t t)
|
|
|
|
|
+{
|
|
|
|
|
+ if (t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Dangerous asynchronous cancelling */
|
|
|
|
|
+ CONTEXT ctxt;
|
|
|
|
|
+
|
|
|
|
|
+ /* Already done? */
|
|
|
|
|
+ if (t->cancelled) return ESRCH;
|
|
|
|
|
+
|
|
|
|
|
+ ctxt.ContextFlags = CONTEXT_CONTROL;
|
|
|
|
|
+
|
|
|
|
|
+ SuspendThread(t->h);
|
|
|
|
|
+ GetThreadContext(t->h, &ctxt);
|
|
|
|
|
+#ifdef _M_X64
|
|
|
|
|
+ ctxt.Rip = (uintptr_t) _pthread_invoke_cancel;
|
|
|
|
|
+#else
|
|
|
|
|
+ ctxt.Eip = (uintptr_t) _pthread_invoke_cancel;
|
|
|
|
|
+#endif
|
|
|
|
|
+ SetThreadContext(t->h, &ctxt);
|
|
|
|
|
+
|
|
|
|
|
+ /* Also try deferred Cancelling */
|
|
|
|
|
+ t->cancelled = 1;
|
|
|
|
|
+
|
|
|
|
|
+ /* Notify everyone to look */
|
|
|
|
|
+ _InterlockedIncrement(&_pthread_cancelling);
|
|
|
|
|
+
|
|
|
|
|
+ ResumeThread(t->h);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Safe deferred Cancelling */
|
|
|
|
|
+ t->cancelled = 1;
|
|
|
|
|
+
|
|
|
|
|
+ /* Notify everyone to look */
|
|
|
|
|
+ _InterlockedIncrement(&_pthread_cancelling);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static unsigned _pthread_get_state(pthread_attr_t *attr, unsigned flag)
|
|
|
|
|
+{
|
|
|
|
|
+ return attr->p_state & flag;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int _pthread_set_state(pthread_attr_t *attr, unsigned flag, unsigned val)
|
|
|
|
|
+{
|
|
|
|
|
+ if (~flag & val) return EINVAL;
|
|
|
|
|
+ attr->p_state &= ~flag;
|
|
|
|
|
+ attr->p_state |= val;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_init(pthread_attr_t *attr)
|
|
|
|
|
+{
|
|
|
|
|
+ attr->p_state = PTHREAD_DEFAULT_ATTR;
|
|
|
|
|
+ attr->stack = NULL;
|
|
|
|
|
+ attr->s_size = 0;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_destroy(pthread_attr_t *attr)
|
|
|
|
|
+{
|
|
|
|
|
+ /* No need to do anything */
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_setdetachstate(pthread_attr_t *a, int flag)
|
|
|
|
|
+{
|
|
|
|
|
+ return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_getdetachstate(pthread_attr_t *a, int *flag)
|
|
|
|
|
+{
|
|
|
|
|
+ *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_setinheritsched(pthread_attr_t *a, int flag)
|
|
|
|
|
+{
|
|
|
|
|
+ return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_getinheritsched(pthread_attr_t *a, int *flag)
|
|
|
|
|
+{
|
|
|
|
|
+ *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_setscope(pthread_attr_t *a, int flag)
|
|
|
|
|
+{
|
|
|
|
|
+ return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_getscope(pthread_attr_t *a, int *flag)
|
|
|
|
|
+{
|
|
|
|
|
+ *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stack)
|
|
|
|
|
+{
|
|
|
|
|
+ *stack = attr->stack;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack)
|
|
|
|
|
+{
|
|
|
|
|
+ attr->stack = stack;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *size)
|
|
|
|
|
+{
|
|
|
|
|
+ *size = attr->s_size;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size)
|
|
|
|
|
+{
|
|
|
|
|
+ attr->s_size = size;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define pthread_attr_getguardsize(A, S) ENOTSUP
|
|
|
|
|
+#define pthread_attr_setgaurdsize(A, S) ENOTSUP
|
|
|
|
|
+#define pthread_attr_getschedparam(A, S) ENOTSUP
|
|
|
|
|
+#define pthread_attr_setschedparam(A, S) ENOTSUP
|
|
|
|
|
+#define pthread_attr_getschedpolicy(A, S) ENOTSUP
|
|
|
|
|
+#define pthread_attr_setschedpolicy(A, S) ENOTSUP
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_setcancelstate(int state, int *oldstate)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_t t = pthread_self();
|
|
|
|
|
+
|
|
|
|
|
+ if ((state & PTHREAD_CANCEL_ENABLE) != state) return EINVAL;
|
|
|
|
|
+ if (oldstate) *oldstate = t->p_state & PTHREAD_CANCEL_ENABLE;
|
|
|
|
|
+ t->p_state &= ~PTHREAD_CANCEL_ENABLE;
|
|
|
|
|
+ t->p_state |= state;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_setcanceltype(int type, int *oldtype)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_t t = pthread_self();
|
|
|
|
|
+
|
|
|
|
|
+ if ((type & PTHREAD_CANCEL_ASYNCHRONOUS) != type) return EINVAL;
|
|
|
|
|
+ if (oldtype) *oldtype = t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS;
|
|
|
|
|
+ t->p_state &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
|
|
|
|
|
+ t->p_state |= type;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_create_wrapper(void *args)
|
|
|
|
|
+{
|
|
|
|
|
+ struct _pthread_v *tv = args;
|
|
|
|
|
+ int i, j;
|
|
|
|
|
+
|
|
|
|
|
+ _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
|
|
|
|
|
+
|
|
|
|
|
+ TlsSetValue(_pthread_tls, tv);
|
|
|
|
|
+
|
|
|
|
|
+ if (!setjmp(tv->jb))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Call function and save return value */
|
|
|
|
|
+ tv->ret_arg = tv->func(tv->ret_arg);
|
|
|
|
|
+
|
|
|
|
|
+ /* Clean up destructors */
|
|
|
|
|
+ _pthread_cleanup_dest(tv);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* If we exit too early, then we can race with create */
|
|
|
|
|
+ while (tv->h == (HANDLE) -1)
|
|
|
|
|
+ {
|
|
|
|
|
+ YieldProcessor();
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Make sure we free ourselves if we are detached */
|
|
|
|
|
+ if (!tv->h) free(tv);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_create(pthread_t *th, pthread_attr_t *attr, void *(* func)(void *), void *arg)
|
|
|
|
|
+{
|
|
|
|
|
+ struct _pthread_v *tv = malloc(sizeof(struct _pthread_v));
|
|
|
|
|
+ unsigned ssize = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (!tv) return 1;
|
|
|
|
|
+
|
|
|
|
|
+ *th = tv;
|
|
|
|
|
+
|
|
|
|
|
+ /* Save data in pthread_t */
|
|
|
|
|
+ tv->ret_arg = arg;
|
|
|
|
|
+ tv->func = func;
|
|
|
|
|
+ tv->clean = NULL;
|
|
|
|
|
+ tv->cancelled = 0;
|
|
|
|
|
+ tv->p_state = PTHREAD_DEFAULT_ATTR;
|
|
|
|
|
+ tv->keymax = 0;
|
|
|
|
|
+ tv->keyval = NULL;
|
|
|
|
|
+ tv->h = (HANDLE) -1;
|
|
|
|
|
+
|
|
|
|
|
+ if (attr)
|
|
|
|
|
+ {
|
|
|
|
|
+ tv->p_state = attr->p_state;
|
|
|
|
|
+ ssize = attr->s_size;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Make sure tv->h has value of -1 */
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+
|
|
|
|
|
+ tv->h = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0, NULL);
|
|
|
|
|
+
|
|
|
|
|
+ /* Failed */
|
|
|
|
|
+ if (!tv->h) return 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (tv->p_state & PTHREAD_CREATE_DETACHED)
|
|
|
|
|
+ {
|
|
|
|
|
+ CloseHandle(tv->h);
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+ tv->h = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_join(pthread_t t, void **res)
|
|
|
|
|
+{
|
|
|
|
|
+ struct _pthread_v *tv = t;
|
|
|
|
|
+
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+
|
|
|
|
|
+ WaitForSingleObject(tv->h, INFINITE);
|
|
|
|
|
+ CloseHandle(tv->h);
|
|
|
|
|
+
|
|
|
|
|
+ /* Obtain return value */
|
|
|
|
|
+ if (res) *res = tv->ret_arg;
|
|
|
|
|
+
|
|
|
|
|
+ free(tv);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_detach(pthread_t t)
|
|
|
|
|
+{
|
|
|
|
|
+ struct _pthread_v *tv = t;
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * This can't race with thread exit because
|
|
|
|
|
+ * our call would be undefined if called on a dead thread.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ CloseHandle(tv->h);
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+ tv->h = 0;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_init(pthread_mutexattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ *a = 0;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) a;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_gettype(pthread_mutexattr_t *a, int *type)
|
|
|
|
|
+{
|
|
|
|
|
+ *type = *a & 3;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
|
|
|
|
|
+{
|
|
|
|
|
+ if ((unsigned) type > 3) return EINVAL;
|
|
|
|
|
+ *a &= ~3;
|
|
|
|
|
+ *a |= type;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_getpshared(pthread_mutexattr_t *a, int *type)
|
|
|
|
|
+{
|
|
|
|
|
+ *type = *a & 4;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type)
|
|
|
|
|
+{
|
|
|
|
|
+ if ((type & 4) != type) return EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ *a &= ~4;
|
|
|
|
|
+ *a |= type;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a, int *type)
|
|
|
|
|
+{
|
|
|
|
|
+ *type = *a & (8 + 16);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type)
|
|
|
|
|
+{
|
|
|
|
|
+ if ((type & (8 + 16)) != 8 + 16) return EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ *a &= ~(8 + 16);
|
|
|
|
|
+ *a |= type;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a, int * prio)
|
|
|
|
|
+{
|
|
|
|
|
+ *prio = *a / PTHREAD_PRIO_MULT;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio)
|
|
|
|
|
+{
|
|
|
|
|
+ *a &= (PTHREAD_PRIO_MULT - 1);
|
|
|
|
|
+ *a += prio * PTHREAD_PRIO_MULT;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_mutex_timedlock(pthread_mutex_t *m, struct timespec *ts)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long long t, ct;
|
|
|
|
|
+
|
|
|
|
|
+ struct _pthread_crit_t
|
|
|
|
|
+ {
|
|
|
|
|
+ void *debug;
|
|
|
|
|
+ LONG count;
|
|
|
|
|
+ LONG r_count;
|
|
|
|
|
+ HANDLE owner;
|
|
|
|
|
+ HANDLE sem;
|
|
|
|
|
+ ULONG_PTR spin;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ /* Try to lock it without waiting */
|
|
|
|
|
+ if (!pthread_mutex_trylock(m)) return 0;
|
|
|
|
|
+
|
|
|
|
|
+ ct = _pthread_time_in_ms();
|
|
|
|
|
+ t = _pthread_time_in_ms_from_timespec(ts);
|
|
|
|
|
+
|
|
|
|
|
+ while (1)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Have we waited long enough? */
|
|
|
|
|
+ if (ct > t) return ETIMEDOUT;
|
|
|
|
|
+
|
|
|
|
|
+ /* Wait on semaphore within critical section */
|
|
|
|
|
+ WaitForSingleObject(((struct _pthread_crit_t *)m)->sem, t - ct);
|
|
|
|
|
+
|
|
|
|
|
+ /* Try to grab lock */
|
|
|
|
|
+ if (!pthread_mutex_trylock(m)) return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* Get current time */
|
|
|
|
|
+ ct = _pthread_time_in_ms();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define _PTHREAD_BARRIER_FLAG (1<<30)
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrier_destroy(pthread_barrier_t *b)
|
|
|
|
|
+{
|
|
|
|
|
+ EnterCriticalSection(&b->m);
|
|
|
|
|
+
|
|
|
|
|
+ while (b->total > _PTHREAD_BARRIER_FLAG)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Wait until everyone exits the barrier */
|
|
|
|
|
+ SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LeaveCriticalSection(&b->m);
|
|
|
|
|
+
|
|
|
|
|
+ DeleteCriticalSection(&b->m);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrier_init(pthread_barrier_t *b, void *attr, int count)
|
|
|
|
|
+{
|
|
|
|
|
+ /* Ignore attr */
|
|
|
|
|
+ (void) attr;
|
|
|
|
|
+
|
|
|
|
|
+ b->count = count;
|
|
|
|
|
+ b->total = 0;
|
|
|
|
|
+
|
|
|
|
|
+ InitializeCriticalSection(&b->m);
|
|
|
|
|
+ InitializeConditionVariable(&b->cv);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrier_wait(pthread_barrier_t *b)
|
|
|
|
|
+{
|
|
|
|
|
+ EnterCriticalSection(&b->m);
|
|
|
|
|
+
|
|
|
|
|
+ while (b->total > _PTHREAD_BARRIER_FLAG)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Wait until everyone exits the barrier */
|
|
|
|
|
+ SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Are we the first to enter? */
|
|
|
|
|
+ if (b->total == _PTHREAD_BARRIER_FLAG) b->total = 0;
|
|
|
|
|
+
|
|
|
|
|
+ b->total++;
|
|
|
|
|
+
|
|
|
|
|
+ if (b->total == b->count)
|
|
|
|
|
+ {
|
|
|
|
|
+ b->total += _PTHREAD_BARRIER_FLAG - 1;
|
|
|
|
|
+ WakeAllConditionVariable(&b->cv);
|
|
|
|
|
+
|
|
|
|
|
+ LeaveCriticalSection(&b->m);
|
|
|
|
|
+
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ while (b->total < _PTHREAD_BARRIER_FLAG)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Wait until enough threads enter the barrier */
|
|
|
|
|
+ SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ b->total--;
|
|
|
|
|
+
|
|
|
|
|
+ /* Get entering threads to wake up */
|
|
|
|
|
+ if (b->total == _PTHREAD_BARRIER_FLAG) WakeAllConditionVariable(&b->cv);
|
|
|
|
|
+
|
|
|
|
|
+ LeaveCriticalSection(&b->m);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrierattr_init(void **attr)
|
|
|
|
|
+{
|
|
|
|
|
+ *attr = NULL;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrierattr_destroy(void **attr)
|
|
|
|
|
+{
|
|
|
|
|
+ /* Ignore attr */
|
|
|
|
|
+ (void) attr;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrierattr_setpshared(void **attr, int s)
|
|
|
|
|
+{
|
|
|
|
|
+ *attr = (void *) s;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_barrierattr_getpshared(void **attr, int *s)
|
|
|
|
|
+{
|
|
|
|
|
+ *s = (int) (size_t) *attr;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_key_create(pthread_key_t *key, void (* dest)(void *))
|
|
|
|
|
+{
|
|
|
|
|
+ int i;
|
|
|
|
|
+ long nmax;
|
|
|
|
|
+ void (**d)(void *);
|
|
|
|
|
+
|
|
|
|
|
+ if (!key) return EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ pthread_rwlock_wrlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ for (i = _pthread_key_sch; i < _pthread_key_max; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!_pthread_key_dest[i])
|
|
|
|
|
+ {
|
|
|
|
|
+ *key = i;
|
|
|
|
|
+ if (dest)
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_key_dest[i] = dest;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_key_dest[i] = (void(*)(void *))1;
|
|
|
|
|
+ }
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < _pthread_key_sch; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!_pthread_key_dest[i])
|
|
|
|
|
+ {
|
|
|
|
|
+ *key = i;
|
|
|
|
|
+ if (dest)
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_key_dest[i] = dest;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_key_dest[i] = (void(*)(void *))1;
|
|
|
|
|
+ }
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!_pthread_key_max) _pthread_key_max = 1;
|
|
|
|
|
+ if (_pthread_key_max == PTHREAD_KEYS_MAX)
|
|
|
|
|
+ {
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return ENOMEM;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ nmax = _pthread_key_max * 2;
|
|
|
|
|
+ if (nmax > PTHREAD_KEYS_MAX) nmax = PTHREAD_KEYS_MAX;
|
|
|
|
|
+
|
|
|
|
|
+ /* No spare room anywhere */
|
|
|
|
|
+ d = realloc(_pthread_key_dest, nmax * sizeof(*d));
|
|
|
|
|
+ if (!d)
|
|
|
|
|
+ {
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return ENOMEM;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Clear new region */
|
|
|
|
|
+ memset((void *) &d[_pthread_key_max], 0, (nmax-_pthread_key_max)*sizeof(void *));
|
|
|
|
|
+
|
|
|
|
|
+ /* Use new region */
|
|
|
|
|
+ _pthread_key_dest = d;
|
|
|
|
|
+ _pthread_key_sch = _pthread_key_max + 1;
|
|
|
|
|
+ *key = _pthread_key_max;
|
|
|
|
|
+ _pthread_key_max = nmax;
|
|
|
|
|
+
|
|
|
|
|
+ if (dest)
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_key_dest[*key] = dest;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ _pthread_key_dest[*key] = (void(*)(void *))1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_key_delete(pthread_key_t key)
|
|
|
|
|
+{
|
|
|
|
|
+ if (key > _pthread_key_max) return EINVAL;
|
|
|
|
|
+ if (!_pthread_key_dest) return EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ pthread_rwlock_wrlock(&_pthread_key_lock);
|
|
|
|
|
+ _pthread_key_dest[key] = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ /* Start next search from our location */
|
|
|
|
|
+ if (_pthread_key_sch > key) _pthread_key_sch = key;
|
|
|
|
|
+
|
|
|
|
|
+ pthread_rwlock_unlock(&_pthread_key_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void *pthread_getspecific(pthread_key_t key)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_t t = pthread_self();
|
|
|
|
|
+
|
|
|
|
|
+ if (key >= t->keymax) return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ return t->keyval[key];
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_setspecific(pthread_key_t key, const void *value)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_t t = pthread_self();
|
|
|
|
|
+
|
|
|
|
|
+ if (key > t->keymax)
|
|
|
|
|
+ {
|
|
|
|
|
+ int keymax = (key + 1) * 2;
|
|
|
|
|
+ void **kv = realloc(t->keyval, keymax * sizeof(void *));
|
|
|
|
|
+
|
|
|
|
|
+ if (!kv) return ENOMEM;
|
|
|
|
|
+
|
|
|
|
|
+ /* Clear new region */
|
|
|
|
|
+ memset(&kv[t->keymax], 0, (keymax - t->keymax)*sizeof(void*));
|
|
|
|
|
+
|
|
|
|
|
+ t->keyval = kv;
|
|
|
|
|
+ t->keymax = keymax;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ t->keyval[key] = (void *) value;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_spin_init(pthread_spinlock_t *l, int pshared)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) pshared;
|
|
|
|
|
+
|
|
|
|
|
+ *l = 0;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_spin_destroy(pthread_spinlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) l;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* No-fair spinlock due to lack of knowledge of thread number */
|
|
|
|
|
+static int pthread_spin_lock(pthread_spinlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ while (_InterlockedExchange(l, EBUSY))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Don't lock the bus whilst waiting */
|
|
|
|
|
+ while (*l)
|
|
|
|
|
+ {
|
|
|
|
|
+ YieldProcessor();
|
|
|
|
|
+
|
|
|
|
|
+ /* Compiler barrier. Prevent caching of *l */
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_spin_trylock(pthread_spinlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ return _InterlockedExchange(l, EBUSY);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_spin_unlock(pthread_spinlock_t *l)
|
|
|
|
|
+{
|
|
|
|
|
+ /* Compiler barrier. The store below acts with release symmantics */
|
|
|
|
|
+ _ReadWriteBarrier();
|
|
|
|
|
+
|
|
|
|
|
+ *l = 0;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cond_init(pthread_cond_t *c, pthread_condattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) a;
|
|
|
|
|
+
|
|
|
|
|
+ InitializeConditionVariable(c);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cond_signal(pthread_cond_t *c)
|
|
|
|
|
+{
|
|
|
|
|
+ WakeConditionVariable(c);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cond_broadcast(pthread_cond_t *c)
|
|
|
|
|
+{
|
|
|
|
|
+ WakeAllConditionVariable(c);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
|
|
|
|
|
+{
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+ SleepConditionVariableCS(c, m, INFINITE);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cond_destroy(pthread_cond_t *c)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) c;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, struct timespec *t)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long long tm = _pthread_rel_time_in_ms(t);
|
|
|
|
|
+
|
|
|
|
|
+ pthread_testcancel();
|
|
|
|
|
+
|
|
|
|
|
+ if (!SleepConditionVariableCS(c, m, tm)) return ETIMEDOUT;
|
|
|
|
|
+
|
|
|
|
|
+ /* We can have a spurious wakeup after the timeout */
|
|
|
|
|
+ if (!_pthread_rel_time_in_ms(t)) return ETIMEDOUT;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_condattr_destroy(pthread_condattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) a;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define pthread_condattr_getclock(A, C) ENOTSUP
|
|
|
|
|
+#define pthread_condattr_setclock(A, C) ENOTSUP
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_condattr_init(pthread_condattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ *a = 0;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
|
|
|
|
|
+{
|
|
|
|
|
+ *s = *a;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
|
|
|
|
|
+{
|
|
|
|
|
+ *a = s;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ (void) a;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlockattr_init(pthread_rwlockattr_t *a)
|
|
|
|
|
+{
|
|
|
|
|
+ *a = 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s)
|
|
|
|
|
+{
|
|
|
|
|
+ *s = *a;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s)
|
|
|
|
|
+{
|
|
|
|
|
+ *a = s;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* No fork() in windows - so ignore this */
|
|
|
|
|
+#define pthread_atfork(F1,F2,F3) 0
|
|
|
|
|
+
|
|
|
|
|
+/* Windows has rudimentary signals support */
|
|
|
|
|
+#define pthread_kill(T, S) 0
|
|
|
|
|
+#define pthread_sigmask(H, S1, S2) 0
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* Wrap cancellation points */
|
|
|
|
|
+#define accept(...) (pthread_testcancel(), accept(__VA_ARGS__))
|
|
|
|
|
+#define aio_suspend(...) (pthread_testcancel(), aio_suspend(__VA_ARGS__))
|
|
|
|
|
+#define clock_nanosleep(...) (pthread_testcancel(), clock_nanosleep(__VA_ARGS__))
|
|
|
|
|
+#define close(...) (pthread_testcancel(), close(__VA_ARGS__))
|
|
|
|
|
+#define connect(...) (pthread_testcancel(), connect(__VA_ARGS__))
|
|
|
|
|
+#define creat(...) (pthread_testcancel(), creat(__VA_ARGS__))
|
|
|
|
|
+#define fcntl(...) (pthread_testcancel(), fcntl(__VA_ARGS__))
|
|
|
|
|
+#define fdatasync(...) (pthread_testcancel(), fdatasync(__VA_ARGS__))
|
|
|
|
|
+#define fsync(...) (pthread_testcancel(), fsync(__VA_ARGS__))
|
|
|
|
|
+#define getmsg(...) (pthread_testcancel(), getmsg(__VA_ARGS__))
|
|
|
|
|
+#define getpmsg(...) (pthread_testcancel(), getpmsg(__VA_ARGS__))
|
|
|
|
|
+#define lockf(...) (pthread_testcancel(), lockf(__VA_ARGS__))
|
|
|
|
|
+#define mg_receive(...) (pthread_testcancel(), mg_receive(__VA_ARGS__))
|
|
|
|
|
+#define mg_send(...) (pthread_testcancel(), mg_send(__VA_ARGS__))
|
|
|
|
|
+#define mg_timedreceive(...) (pthread_testcancel(), mg_timedreceive(__VA_ARGS__))
|
|
|
|
|
+#define mg_timessend(...) (pthread_testcancel(), mg_timedsend(__VA_ARGS__))
|
|
|
|
|
+#define msgrcv(...) (pthread_testcancel(), msgrecv(__VA_ARGS__))
|
|
|
|
|
+#define msgsnd(...) (pthread_testcancel(), msgsnd(__VA_ARGS__))
|
|
|
|
|
+#define msync(...) (pthread_testcancel(), msync(__VA_ARGS__))
|
|
|
|
|
+#define nanosleep(...) (pthread_testcancel(), nanosleep(__VA_ARGS__))
|
|
|
|
|
+#define open(...) (pthread_testcancel(), open(__VA_ARGS__))
|
|
|
|
|
+#define pause(...) (pthread_testcancel(), pause(__VA_ARGS__))
|
|
|
|
|
+#define poll(...) (pthread_testcancel(), poll(__VA_ARGS__))
|
|
|
|
|
+#define pread(...) (pthread_testcancel(), pread(__VA_ARGS__))
|
|
|
|
|
+#define pselect(...) (pthread_testcancel(), pselect(__VA_ARGS__))
|
|
|
|
|
+#define putmsg(...) (pthread_testcancel(), putmsg(__VA_ARGS__))
|
|
|
|
|
+#define putpmsg(...) (pthread_testcancel(), putpmsg(__VA_ARGS__))
|
|
|
|
|
+#define pwrite(...) (pthread_testcancel(), pwrite(__VA_ARGS__))
|
|
|
|
|
+#define read(...) (pthread_testcancel(), read(__VA_ARGS__))
|
|
|
|
|
+#define readv(...) (pthread_testcancel(), readv(__VA_ARGS__))
|
|
|
|
|
+#define recv(...) (pthread_testcancel(), recv(__VA_ARGS__))
|
|
|
|
|
+#define recvfrom(...) (pthread_testcancel(), recvfrom(__VA_ARGS__))
|
|
|
|
|
+#define recvmsg(...) (pthread_testcancel(), recvmsg(__VA_ARGS__))
|
|
|
|
|
+#define select(...) (pthread_testcancel(), select(__VA_ARGS__))
|
|
|
|
|
+#define sem_timedwait(...) (pthread_testcancel(), sem_timedwait(__VA_ARGS__))
|
|
|
|
|
+#define sem_wait(...) (pthread_testcancel(), sem_wait(__VA_ARGS__))
|
|
|
|
|
+#define send(...) (pthread_testcancel(), send(__VA_ARGS__))
|
|
|
|
|
+#define sendmsg(...) (pthread_testcancel(), sendmsg(__VA_ARGS__))
|
|
|
|
|
+#define sendto(...) (pthread_testcancel(), sendto(__VA_ARGS__))
|
|
|
|
|
+#define sigpause(...) (pthread_testcancel(), sigpause(__VA_ARGS__))
|
|
|
|
|
+#define sigsuspend(...) (pthread_testcancel(), sigsuspend(__VA_ARGS__))
|
|
|
|
|
+#define sigwait(...) (pthread_testcancel(), sigwait(__VA_ARGS__))
|
|
|
|
|
+#define sigwaitinfo(...) (pthread_testcancel(), sigwaitinfo(__VA_ARGS__))
|
|
|
|
|
+#define sleep(...) (pthread_testcancel(), sleep(__VA_ARGS__))
|
|
|
|
|
+//#define Sleep(...) (pthread_testcancel(), Sleep(__VA_ARGS__))
|
|
|
|
|
+#define system(...) (pthread_testcancel(), system(__VA_ARGS__))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#define access(...) (pthread_testcancel(), access(__VA_ARGS__))
|
|
|
|
|
+#define asctime(...) (pthread_testcancel(), asctime(__VA_ARGS__))
|
|
|
|
|
+#define asctime_r(...) (pthread_testcancel(), asctime_r(__VA_ARGS__))
|
|
|
|
|
+#define catclose(...) (pthread_testcancel(), catclose(__VA_ARGS__))
|
|
|
|
|
+#define catgets(...) (pthread_testcancel(), catgets(__VA_ARGS__))
|
|
|
|
|
+#define catopen(...) (pthread_testcancel(), catopen(__VA_ARGS__))
|
|
|
|
|
+#define closedir(...) (pthread_testcancel(), closedir(__VA_ARGS__))
|
|
|
|
|
+#define closelog(...) (pthread_testcancel(), closelog(__VA_ARGS__))
|
|
|
|
|
+#define ctermid(...) (pthread_testcancel(), ctermid(__VA_ARGS__))
|
|
|
|
|
+#define ctime(...) (pthread_testcancel(), ctime(__VA_ARGS__))
|
|
|
|
|
+#define ctime_r(...) (pthread_testcancel(), ctime_r(__VA_ARGS__))
|
|
|
|
|
+#define dbm_close(...) (pthread_testcancel(), dbm_close(__VA_ARGS__))
|
|
|
|
|
+#define dbm_delete(...) (pthread_testcancel(), dbm_delete(__VA_ARGS__))
|
|
|
|
|
+#define dbm_fetch(...) (pthread_testcancel(), dbm_fetch(__VA_ARGS__))
|
|
|
|
|
+#define dbm_nextkey(...) (pthread_testcancel(), dbm_nextkey(__VA_ARGS__))
|
|
|
|
|
+#define dbm_open(...) (pthread_testcancel(), dbm_open(__VA_ARGS__))
|
|
|
|
|
+#define dbm_store(...) (pthread_testcancel(), dbm_store(__VA_ARGS__))
|
|
|
|
|
+#define dlclose(...) (pthread_testcancel(), dlclose(__VA_ARGS__))
|
|
|
|
|
+#define dlopen(...) (pthread_testcancel(), dlopen(__VA_ARGS__))
|
|
|
|
|
+#define endgrent(...) (pthread_testcancel(), endgrent(__VA_ARGS__))
|
|
|
|
|
+#define endhostent(...) (pthread_testcancel(), endhostent(__VA_ARGS__))
|
|
|
|
|
+#define endnetent(...) (pthread_testcancel(), endnetent(__VA_ARGS__))
|
|
|
|
|
+#define endprotoent(...) (pthread_testcancel(), endprotoend(__VA_ARGS__))
|
|
|
|
|
+#define endpwent(...) (pthread_testcancel(), endpwent(__VA_ARGS__))
|
|
|
|
|
+#define endservent(...) (pthread_testcancel(), endservent(__VA_ARGS__))
|
|
|
|
|
+#define endutxent(...) (pthread_testcancel(), endutxent(__VA_ARGS__))
|
|
|
|
|
+#define fclose(...) (pthread_testcancel(), fclose(__VA_ARGS__))
|
|
|
|
|
+#define fflush(...) (pthread_testcancel(), fflush(__VA_ARGS__))
|
|
|
|
|
+#define fgetc(...) (pthread_testcancel(), fgetc(__VA_ARGS__))
|
|
|
|
|
+#define fgetpos(...) (pthread_testcancel(), fgetpos(__VA_ARGS__))
|
|
|
|
|
+#define fgets(...) (pthread_testcancel(), fgets(__VA_ARGS__))
|
|
|
|
|
+#define fgetwc(...) (pthread_testcancel(), fgetwc(__VA_ARGS__))
|
|
|
|
|
+#define fgetws(...) (pthread_testcancel(), fgetws(__VA_ARGS__))
|
|
|
|
|
+#define fmtmsg(...) (pthread_testcancel(), fmtmsg(__VA_ARGS__))
|
|
|
|
|
+#define fopen(...) (pthread_testcancel(), fopen(__VA_ARGS__))
|
|
|
|
|
+#define fpathconf(...) (pthread_testcancel(), fpathconf(__VA_ARGS__))
|
|
|
|
|
+#define fprintf(...) (pthread_testcancel(), fprintf(__VA_ARGS__))
|
|
|
|
|
+#define fputc(...) (pthread_testcancel(), fputc(__VA_ARGS__))
|
|
|
|
|
+#define fputs(...) (pthread_testcancel(), fputs(__VA_ARGS__))
|
|
|
|
|
+#define fputwc(...) (pthread_testcancel(), fputwc(__VA_ARGS__))
|
|
|
|
|
+#define fputws(...) (pthread_testcancel(), fputws(__VA_ARGS__))
|
|
|
|
|
+#define fread(...) (pthread_testcancel(), fread(__VA_ARGS__))
|
|
|
|
|
+#define freopen(...) (pthread_testcancel(), freopen(__VA_ARGS__))
|
|
|
|
|
+#define fscanf(...) (pthread_testcancel(), fscanf(__VA_ARGS__))
|
|
|
|
|
+#define fseek(...) (pthread_testcancel(), fseek(__VA_ARGS__))
|
|
|
|
|
+#define fseeko(...) (pthread_testcancel(), fseeko(__VA_ARGS__))
|
|
|
|
|
+#define fsetpos(...) (pthread_testcancel(), fsetpos(__VA_ARGS__))
|
|
|
|
|
+#define fstat(...) (pthread_testcancel(), fstat(__VA_ARGS__))
|
|
|
|
|
+#define ftell(...) (pthread_testcancel(), ftell(__VA_ARGS__))
|
|
|
|
|
+#define ftello(...) (pthread_testcancel(), ftello(__VA_ARGS__))
|
|
|
|
|
+#define ftw(...) (pthread_testcancel(), ftw(__VA_ARGS__))
|
|
|
|
|
+#define fwprintf(...) (pthread_testcancel(), fwprintf(__VA_ARGS__))
|
|
|
|
|
+#define fwrite(...) (pthread_testcancel(), fwrite(__VA_ARGS__))
|
|
|
|
|
+#define fwscanf(...) (pthread_testcancel(), fwscanf(__VA_ARGS__))
|
|
|
|
|
+#define getaddrinfo(...) (pthread_testcancel(), getaddrinfo(__VA_ARGS__))
|
|
|
|
|
+#define getc(...) (pthread_testcancel(), getc(__VA_ARGS__))
|
|
|
|
|
+#define getc_unlocked(...) (pthread_testcancel(), getc_unlocked(__VA_ARGS__))
|
|
|
|
|
+#define getchar(...) (pthread_testcancel(), getchar(__VA_ARGS__))
|
|
|
|
|
+#define getchar_unlocked(...) (pthread_testcancel(), getchar_unlocked(__VA_ARGS__))
|
|
|
|
|
+#define getcwd(...) (pthread_testcancel(), getcwd(__VA_ARGS__))
|
|
|
|
|
+#define getdate(...) (pthread_testcancel(), getdate(__VA_ARGS__))
|
|
|
|
|
+#define getgrent(...) (pthread_testcancel(), getgrent(__VA_ARGS__))
|
|
|
|
|
+#define getgrgid(...) (pthread_testcancel(), getgrgid(__VA_ARGS__))
|
|
|
|
|
+#define getgrgid_r(...) (pthread_testcancel(), getgrgid_r(__VA_ARGS__))
|
|
|
|
|
+#define gergrnam(...) (pthread_testcancel(), getgrnam(__VA_ARGS__))
|
|
|
|
|
+#define getgrnam_r(...) (pthread_testcancel(), getgrnam_r(__VA_ARGS__))
|
|
|
|
|
+#define gethostbyaddr(...) (pthread_testcancel(), gethostbyaddr(__VA_ARGS__))
|
|
|
|
|
+#define gethostbyname(...) (pthread_testcancel(), gethostbyname(__VA_ARGS__))
|
|
|
|
|
+#define gethostent(...) (pthread_testcancel(), gethostent(__VA_ARGS__))
|
|
|
|
|
+#define gethostid(...) (pthread_testcancel(), gethostid(__VA_ARGS__))
|
|
|
|
|
+#define gethostname(...) (pthread_testcancel(), gethostname(__VA_ARGS__))
|
|
|
|
|
+#define getlogin(...) (pthread_testcancel(), getlogin(__VA_ARGS__))
|
|
|
|
|
+#define getlogin_r(...) (pthread_testcancel(), getlogin_r(__VA_ARGS__))
|
|
|
|
|
+#define getnameinfo(...) (pthread_testcancel(), getnameinfo(__VA_ARGS__))
|
|
|
|
|
+#define getnetbyaddr(...) (pthread_testcancel(), getnetbyaddr(__VA_ARGS__))
|
|
|
|
|
+#define getnetbyname(...) (pthread_testcancel(), getnetbyname(__VA_ARGS__))
|
|
|
|
|
+#define getnetent(...) (pthread_testcancel(), getnetent(__VA_ARGS__))
|
|
|
|
|
+#define getopt(...) (pthread_testcancel(), getopt(__VA_ARGS__))
|
|
|
|
|
+#define getprotobyname(...) (pthread_testcancel(), getprotobyname(__VA_ARGS__))
|
|
|
|
|
+#define getprotobynumber(...) (pthread_testcancel(), getprotobynumber(__VA_ARGS__))
|
|
|
|
|
+#define getprotoent(...) (pthread_testcancel(), getprotoent(__VA_ARGS__))
|
|
|
|
|
+#define getpwent(...) (pthread_testcancel(), getpwent(__VA_ARGS__))
|
|
|
|
|
+#define getpwnam(...) (pthread_testcancel(), getpwnam(__VA_ARGS__))
|
|
|
|
|
+#define getpwnam_r(...) (pthread_testcancel(), getpwnam_r(__VA_ARGS__))
|
|
|
|
|
+#define getpwuid(...) (pthread_testcancel(), getpwuid(__VA_ARGS__))
|
|
|
|
|
+#define getpwuid_r(...) (pthread_testcancel(), getpwuid_r(__VA_ARGS__))
|
|
|
|
|
+#define gets(...) (pthread_testcancel(), gets(__VA_ARGS__))
|
|
|
|
|
+#define getservbyname(...) (pthread_testcancel(), getservbyname(__VA_ARGS__))
|
|
|
|
|
+#define getservbyport(...) (pthread_testcancel(), getservbyport(__VA_ARGS__))
|
|
|
|
|
+#define getservent(...) (pthread_testcancel(), getservent(__VA_ARGS__))
|
|
|
|
|
+#define getutxent(...) (pthread_testcancel(), getutxent(__VA_ARGS__))
|
|
|
|
|
+#define getutxid(...) (pthread_testcancel(), getutxid(__VA_ARGS__))
|
|
|
|
|
+#define getutxline(...) (pthread_testcancel(), getutxline(__VA_ARGS__))
|
|
|
|
|
+#undef getwc
|
|
|
|
|
+#define getwc(...) (pthread_testcancel(), getwc(__VA_ARGS__))
|
|
|
|
|
+#undef getwchar
|
|
|
|
|
+#define getwchar(...) (pthread_testcancel(), getwchar(__VA_ARGS__))
|
|
|
|
|
+#define getwd(...) (pthread_testcancel(), getwd(__VA_ARGS__))
|
|
|
|
|
+#define glob(...) (pthread_testcancel(), glob(__VA_ARGS__))
|
|
|
|
|
+#define iconv_close(...) (pthread_testcancel(), iconv_close(__VA_ARGS__))
|
|
|
|
|
+#define iconv_open(...) (pthread_testcancel(), iconv_open(__VA_ARGS__))
|
|
|
|
|
+#define ioctl(...) (pthread_testcancel(), ioctl(__VA_ARGS__))
|
|
|
|
|
+#define link(...) (pthread_testcancel(), link(__VA_ARGS__))
|
|
|
|
|
+#define localtime(...) (pthread_testcancel(), localtime(__VA_ARGS__))
|
|
|
|
|
+#define localtime_r(...) (pthread_testcancel(), localtime_r(__VA_ARGS__))
|
|
|
|
|
+#define lseek(...) (pthread_testcancel(), lseek(__VA_ARGS__))
|
|
|
|
|
+#define lstat(...) (pthread_testcancel(), lstat(__VA_ARGS__))
|
|
|
|
|
+#define mkstemp(...) (pthread_testcancel(), mkstemp(__VA_ARGS__))
|
|
|
|
|
+#define nftw(...) (pthread_testcancel(), nftw(__VA_ARGS__))
|
|
|
|
|
+#define opendir(...) (pthread_testcancel(), opendir(__VA_ARGS__))
|
|
|
|
|
+#define openlog(...) (pthread_testcancel(), openlog(__VA_ARGS__))
|
|
|
|
|
+#define pathconf(...) (pthread_testcancel(), pathconf(__VA_ARGS__))
|
|
|
|
|
+#define pclose(...) (pthread_testcancel(), pclose(__VA_ARGS__))
|
|
|
|
|
+#define perror(...) (pthread_testcancel(), perror(__VA_ARGS__))
|
|
|
|
|
+#define popen(...) (pthread_testcancel(), popen(__VA_ARGS__))
|
|
|
|
|
+#define posix_fadvise(...) (pthread_testcancel(), posix_fadvise(__VA_ARGS__))
|
|
|
|
|
+#define posix_fallocate(...) (pthread_testcancel(), posix_fallocate(__VA_ARGS__))
|
|
|
|
|
+#define posix_madvise(...) (pthread_testcancel(), posix_madvise(__VA_ARGS__))
|
|
|
|
|
+#define posix_openpt(...) (pthread_testcancel(), posix_openpt(__VA_ARGS__))
|
|
|
|
|
+#define posix_spawn(...) (pthread_testcancel(), posix_spawn(__VA_ARGS__))
|
|
|
|
|
+#define posix_spawnp(...) (pthread_testcancel(), posix_spawnp(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_clear(...) (pthread_testcancel(), posix_trace_clear(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_close(...) (pthread_testcancel(), posix_trace_close(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_create(...) (pthread_testcancel(), posix_trace_create(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_create_withlog(...) (pthread_testcancel(), posix_trace_create_withlog(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_eventtypelist_getne(...) (pthread_testcancel(), posix_trace_eventtypelist_getne(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_eventtypelist_rewin(...) (pthread_testcancel(), posix_trace_eventtypelist_rewin(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_flush(...) (pthread_testcancel(), posix_trace_flush(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_get_attr(...) (pthread_testcancel(), posix_trace_get_attr(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_get_filter(...) (pthread_testcancel(), posix_trace_get_filter(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_get_status(...) (pthread_testcancel(), posix_trace_get_status(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_getnext_event(...) (pthread_testcancel(), posix_trace_getnext_event(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_open(...) (pthread_testcancel(), posix_trace_open(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_rewind(...) (pthread_testcancel(), posix_trace_rewind(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_setfilter(...) (pthread_testcancel(), posix_trace_setfilter(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_shutdown(...) (pthread_testcancel(), posix_trace_shutdown(__VA_ARGS__))
|
|
|
|
|
+#define posix_trace_timedgetnext_event(...) (pthread_testcancel(), posix_trace_timedgetnext_event(__VA_ARGS__))
|
|
|
|
|
+#define posix_typed_mem_open(...) (pthread_testcancel(), posix_typed_mem_open(__VA_ARGS__))
|
|
|
|
|
+#define printf(...) (pthread_testcancel(), printf(__VA_ARGS__))
|
|
|
|
|
+#define putc(...) (pthread_testcancel(), putc(__VA_ARGS__))
|
|
|
|
|
+#define putc_unlocked(...) (pthread_testcancel(), putc_unlocked(__VA_ARGS__))
|
|
|
|
|
+#define putchar(...) (pthread_testcancel(), putchar(__VA_ARGS__))
|
|
|
|
|
+#define putchar_unlocked(...) (pthread_testcancel(), putchar_unlocked(__VA_ARGS__))
|
|
|
|
|
+#define puts(...) (pthread_testcancel(), puts(__VA_ARGS__))
|
|
|
|
|
+#define pututxline(...) (pthread_testcancel(), pututxline(__VA_ARGS__))
|
|
|
|
|
+#undef putwc
|
|
|
|
|
+#define putwc(...) (pthread_testcancel(), putwc(__VA_ARGS__))
|
|
|
|
|
+#undef putwchar
|
|
|
|
|
+#define putwchar(...) (pthread_testcancel(), putwchar(__VA_ARGS__))
|
|
|
|
|
+#define readdir(...) (pthread_testcancel(), readdir(__VA_ARSG__))
|
|
|
|
|
+#define readdir_r(...) (pthread_testcancel(), readdir_r(__VA_ARGS__))
|
|
|
|
|
+#define remove(...) (pthread_testcancel(), remove(__VA_ARGS__))
|
|
|
|
|
+#define rename(...) (pthread_testcancel(), rename(__VA_ARGS__))
|
|
|
|
|
+#define rewind(...) (pthread_testcancel(), rewind(__VA_ARGS__))
|
|
|
|
|
+#define rewinddir(...) (pthread_testcancel(), rewinddir(__VA_ARGS__))
|
|
|
|
|
+#define scanf(...) (pthread_testcancel(), scanf(__VA_ARGS__))
|
|
|
|
|
+#define seekdir(...) (pthread_testcancel(), seekdir(__VA_ARGS__))
|
|
|
|
|
+#define semop(...) (pthread_testcancel(), semop(__VA_ARGS__))
|
|
|
|
|
+#define setgrent(...) (pthread_testcancel(), setgrent(__VA_ARGS__))
|
|
|
|
|
+#define sethostent(...) (pthread_testcancel(), sethostemt(__VA_ARGS__))
|
|
|
|
|
+#define setnetent(...) (pthread_testcancel(), setnetent(__VA_ARGS__))
|
|
|
|
|
+#define setprotoent(...) (pthread_testcancel(), setprotoent(__VA_ARGS__))
|
|
|
|
|
+#define setpwent(...) (pthread_testcancel(), setpwent(__VA_ARGS__))
|
|
|
|
|
+#define setservent(...) (pthread_testcancel(), setservent(__VA_ARGS__))
|
|
|
|
|
+#define setutxent(...) (pthread_testcancel(), setutxent(__VA_ARGS__))
|
|
|
|
|
+#define stat(...) (pthread_testcancel(), stat(__VA_ARGS__))
|
|
|
|
|
+#define strerror(...) (pthread_testcancel(), strerror(__VA_ARGS__))
|
|
|
|
|
+#define strerror_r(...) (pthread_testcancel(), strerror_r(__VA_ARGS__))
|
|
|
|
|
+#define strftime(...) (pthread_testcancel(), strftime(__VA_ARGS__))
|
|
|
|
|
+#define symlink(...) (pthread_testcancel(), symlink(__VA_ARGS__))
|
|
|
|
|
+#define sync(...) (pthread_testcancel(), sync(__VA_ARGS__))
|
|
|
|
|
+#define syslog(...) (pthread_testcancel(), syslog(__VA_ARGS__))
|
|
|
|
|
+#define tmpfile(...) (pthread_testcancel(), tmpfile(__VA_ARGS__))
|
|
|
|
|
+#define tmpnam(...) (pthread_testcancel(), tmpnam(__VA_ARGS__))
|
|
|
|
|
+#define ttyname(...) (pthread_testcancel(), ttyname(__VA_ARGS__))
|
|
|
|
|
+#define ttyname_r(...) (pthread_testcancel(), ttyname_r(__VA_ARGS__))
|
|
|
|
|
+#define tzset(...) (pthread_testcancel(), tzset(__VA_ARGS__))
|
|
|
|
|
+#define ungetc(...) (pthread_testcancel(), ungetc(__VA_ARGS__))
|
|
|
|
|
+#define ungetwc(...) (pthread_testcancel(), ungetwc(__VA_ARGS__))
|
|
|
|
|
+#define unlink(...) (pthread_testcancel(), unlink(__VA_ARGS__))
|
|
|
|
|
+#define vfprintf(...) (pthread_testcancel(), vfprintf(__VA_ARGS__))
|
|
|
|
|
+#define vfwprintf(...) (pthread_testcancel(), vfwprintf(__VA_ARGS__))
|
|
|
|
|
+#define vprintf(...) (pthread_testcancel(), vprintf(__VA_ARGS__))
|
|
|
|
|
+#define vwprintf(...) (pthread_testcancel(), vwprintf(__VA_ARGS__))
|
|
|
|
|
+#define wcsftime(...) (pthread_testcancel(), wcsftime(__VA_ARGS__))
|
|
|
|
|
+#define wordexp(...) (pthread_testcancel(), wordexp(__VA_ARGS__))
|
|
|
|
|
+#define wprintf(...) (pthread_testcancel(), wprintf(__VA_ARGS__))
|
|
|
|
|
+#define wscanf(...) (pthread_testcancel(), wscanf(__VA_ARGS__))
|
|
|
|
|
+
|
|
|
|
|
+#endif /* WIN_PTHREADS */
|