aboutsummaryrefslogtreecommitdiff
path: root/vendor/zgui/libs/winpthreads/src
diff options
context:
space:
mode:
authorNic Gaffney <gaffney_nic@protonmail.com>2024-06-12 21:15:52 -0500
committerNic Gaffney <gaffney_nic@protonmail.com>2024-06-12 21:15:52 -0500
commit963fae202108acd0498349e872e4811fa6c6aba0 (patch)
tree1a7d5b6ee837700819d8f6f5a2484342a0ab6ec1 /vendor/zgui/libs/winpthreads/src
parent6084001df845815efd9c0eb712acf4fd9311ce36 (diff)
downloadparticle-sim-963fae202108acd0498349e872e4811fa6c6aba0.tar.gz
Added imgui for configuration
Diffstat (limited to 'vendor/zgui/libs/winpthreads/src')
-rw-r--r--vendor/zgui/libs/winpthreads/src/barrier.c246
-rw-r--r--vendor/zgui/libs/winpthreads/src/barrier.h52
-rw-r--r--vendor/zgui/libs/winpthreads/src/clock.c257
-rw-r--r--vendor/zgui/libs/winpthreads/src/cond.c755
-rw-r--r--vendor/zgui/libs/winpthreads/src/cond.h63
-rw-r--r--vendor/zgui/libs/winpthreads/src/libgcc/dll_math.c586
-rw-r--r--vendor/zgui/libs/winpthreads/src/misc.c197
-rw-r--r--vendor/zgui/libs/winpthreads/src/misc.h126
-rw-r--r--vendor/zgui/libs/winpthreads/src/mutex.c381
-rw-r--r--vendor/zgui/libs/winpthreads/src/nanosleep.c71
-rw-r--r--vendor/zgui/libs/winpthreads/src/ref.c34
-rw-r--r--vendor/zgui/libs/winpthreads/src/ref.h29
-rw-r--r--vendor/zgui/libs/winpthreads/src/rwlock.c537
-rw-r--r--vendor/zgui/libs/winpthreads/src/rwlock.h49
-rw-r--r--vendor/zgui/libs/winpthreads/src/sched.c218
-rw-r--r--vendor/zgui/libs/winpthreads/src/sem.c354
-rw-r--r--vendor/zgui/libs/winpthreads/src/sem.h40
-rw-r--r--vendor/zgui/libs/winpthreads/src/spinlock.c74
-rw-r--r--vendor/zgui/libs/winpthreads/src/thread.c1914
-rw-r--r--vendor/zgui/libs/winpthreads/src/thread.h79
-rw-r--r--vendor/zgui/libs/winpthreads/src/winpthread_internal.h27
-rw-r--r--vendor/zgui/libs/winpthreads/src/wpth_ver.h29
22 files changed, 6118 insertions, 0 deletions
diff --git a/vendor/zgui/libs/winpthreads/src/barrier.c b/vendor/zgui/libs/winpthreads/src/barrier.c
new file mode 100644
index 0000000..e973aaa
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/barrier.c
@@ -0,0 +1,246 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "pthread.h"
+#include "barrier.h"
+#include "ref.h"
+#include "misc.h"
+
+static pthread_spinlock_t barrier_global = PTHREAD_SPINLOCK_INITIALIZER;
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int
+barrier_unref(volatile pthread_barrier_t *barrier, int res)
+{
+ pthread_spin_lock(&barrier_global);
+#ifdef WINPTHREAD_DBG
+ assert((((barrier_t *)*barrier)->valid == LIFE_BARRIER) && (((barrier_t *)*barrier)->busy > 0));
+#endif
+ ((barrier_t *)*barrier)->busy -= 1;
+ pthread_spin_unlock(&barrier_global);
+ return res;
+}
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int barrier_ref(volatile pthread_barrier_t *barrier)
+{
+ int r = 0;
+ pthread_spin_lock(&barrier_global);
+
+ if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL;
+ else {
+ ((barrier_t *)*barrier)->busy += 1;
+ }
+
+ pthread_spin_unlock(&barrier_global);
+
+ return r;
+}
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int
+barrier_ref_destroy(volatile pthread_barrier_t *barrier, pthread_barrier_t *bDestroy)
+{
+ int r = 0;
+
+ *bDestroy = NULL;
+ pthread_spin_lock(&barrier_global);
+
+ if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL;
+ else {
+ barrier_t *b_ = (barrier_t *)*barrier;
+ if (b_->busy) r = EBUSY;
+ else {
+ *bDestroy = *barrier;
+ *barrier = NULL;
+ }
+ }
+
+ pthread_spin_unlock(&barrier_global);
+ return r;
+}
+
+static WINPTHREADS_ATTRIBUTE((noinline)) void
+barrier_ref_set (volatile pthread_barrier_t *barrier, void *v)
+{
+ pthread_spin_lock(&barrier_global);
+ *barrier = v;
+ pthread_spin_unlock(&barrier_global);
+}
+
+int pthread_barrier_destroy(pthread_barrier_t *b_)
+{
+ pthread_barrier_t bDestroy;
+ barrier_t *b;
+ int r;
+
+ while ((r = barrier_ref_destroy(b_,&bDestroy)) == EBUSY)
+ Sleep(0);
+
+ if (r)
+ return r;
+
+ b = (barrier_t *)bDestroy;
+
+ pthread_mutex_lock(&b->m);
+
+ if (sem_destroy(&b->sems[0]) != 0)
+ {
+ /* Could this happen? */
+ *b_ = bDestroy;
+ pthread_mutex_unlock (&b->m);
+ return EBUSY;
+ }
+ if (sem_destroy(&b->sems[1]) != 0)
+ {
+ sem_init (&b->sems[0], b->share, 0);
+ *b_ = bDestroy;
+ pthread_mutex_unlock (&b->m);
+ return -1;
+ }
+ pthread_mutex_unlock(&b->m);
+ if(pthread_mutex_destroy(&b->m) != 0) {
+ sem_init (&b->sems[0], b->share, 0);
+ sem_init (&b->sems[1], b->share, 0);
+ *b_ = bDestroy;
+ return -1;
+ }
+ b->valid = DEAD_BARRIER;
+ free(bDestroy);
+ return 0;
+
+}
+
+int
+pthread_barrier_init (pthread_barrier_t *b_, const void *attr,
+ unsigned int count)
+{
+ barrier_t *b;
+
+ if (!count || !b_)
+ return EINVAL;
+
+ if ((b = (pthread_barrier_t)calloc(1,sizeof(*b))) == NULL)
+ return ENOMEM;
+ if (!attr || *((int **)attr) == NULL)
+ b->share = PTHREAD_PROCESS_PRIVATE;
+ else
+ memcpy (&b->share, *((void **) attr), sizeof (int));
+ b->total = count;
+ b->count = count;
+ b->valid = LIFE_BARRIER;
+ b->sel = 0;
+
+ if (pthread_mutex_init(&b->m, NULL) != 0)
+ {
+ free (b);
+ return ENOMEM;
+ }
+
+ if (sem_init(&b->sems[0], b->share, 0) != 0)
+ {
+ pthread_mutex_destroy(&b->m);
+ free (b);
+ return ENOMEM;
+ }
+ if (sem_init(&b->sems[1], b->share, 0) != 0)
+ {
+ pthread_mutex_destroy(&b->m);
+ sem_destroy(&b->sems[0]);
+ free (b);
+ return ENOMEM;
+ }
+ barrier_ref_set (b_,b);
+
+ return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t *b_)
+{
+ long sel;
+ int r, e, rslt;
+ barrier_t *b;
+
+ r = barrier_ref(b_);
+ if(r) return r;
+
+ b = (barrier_t *)*b_;
+
+ if ((r = pthread_mutex_lock(&b->m)) != 0) return barrier_unref(b_,EINVAL);
+ sel = b->sel;
+ InterlockedDecrement((long*)&b->total);
+ if (b->total == 0)
+ {
+ b->total = b->count;
+ b->sel = (sel != 0 ? 0 : 1);
+ e = 1;
+ rslt = PTHREAD_BARRIER_SERIAL_THREAD;
+ r = (b->count > 1 ? sem_post_multiple (&b->sems[sel], b->count - 1) : 0);
+ }
+ else { e = 0; rslt= 0; }
+ pthread_mutex_unlock(&b->m);
+ if (!e)
+ r = sem_wait(&b->sems[sel]);
+
+ if (!r) r = rslt;
+ return barrier_unref(b_,r);
+}
+
+int pthread_barrierattr_init(void **attr)
+{
+ int *p;
+
+ if ((p = (int *) calloc (1, sizeof (int))) == NULL)
+ return ENOMEM;
+
+ *p = PTHREAD_PROCESS_PRIVATE;
+ *attr = p;
+
+ return 0;
+}
+
+int pthread_barrierattr_destroy(void **attr)
+{
+ void *p;
+ if (!attr || (p = *attr) == NULL)
+ return EINVAL;
+ *attr = NULL;
+ free (p);
+ return 0;
+}
+
+int pthread_barrierattr_setpshared(void **attr, int s)
+{
+ if (!attr || *attr == NULL
+ || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
+ return EINVAL;
+ memcpy (*attr, &s, sizeof (int));
+ return 0;
+}
+
+int pthread_barrierattr_getpshared(void **attr, int *s)
+{
+ if (!attr || !s || *attr == NULL)
+ return EINVAL;
+ memcpy (s, *attr, sizeof (int));
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/barrier.h b/vendor/zgui/libs/winpthreads/src/barrier.h
new file mode 100644
index 0000000..5509678
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/barrier.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_PTHREADS_BARRIER_H
+#define WIN_PTHREADS_BARRIER_H
+
+#define LIFE_BARRIER 0xBAB1FEED
+#define DEAD_BARRIER 0xDEADB00F
+
+#define _PTHREAD_BARRIER_FLAG (1<<30)
+
+#define CHECK_BARRIER(b) \
+ do { \
+ if (!(b) || ( ((barrier_t *)(*b))->valid != (unsigned int)LIFE_BARRIER ) ) \
+ return EINVAL; \
+ } while (0)
+
+#include "semaphore.h"
+
+typedef struct barrier_t barrier_t;
+struct barrier_t
+{
+ int valid;
+ int busy;
+ int count;
+ int total;
+ int share;
+ long sel;
+ pthread_mutex_t m;
+ sem_t sems[2];
+};
+
+#endif
diff --git a/vendor/zgui/libs/winpthreads/src/clock.c b/vendor/zgui/libs/winpthreads/src/clock.c
new file mode 100644
index 0000000..954d845
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/clock.c
@@ -0,0 +1,257 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <time.h>
+#include <windows.h>
+#ifndef IN_WINPTHREAD
+#define IN_WINPTHREAD 1
+#endif
+#include "pthread.h"
+#include "pthread_time.h"
+#include "misc.h"
+
+#define POW10_7 10000000
+#define POW10_9 1000000000
+
+/* Number of 100ns-seconds between the beginning of the Windows epoch
+ * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970)
+ */
+#define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000)
+
+static WINPTHREADS_INLINE int lc_set_errno(int result)
+{
+ if (result != 0) {
+ errno = result;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Get the resolution of the specified clock clock_id and
+ * stores it in the struct timespec pointed to by res.
+ * @param clock_id The clock_id argument is the identifier of the particular
+ * clock on which to act. The following clocks are supported:
+ * <pre>
+ * CLOCK_REALTIME System-wide real-time clock. Setting this clock
+ * requires appropriate privileges.
+ * CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
+ * time since some unspecified starting point.
+ * CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
+ * CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
+ * </pre>
+ * @param res The pointer to a timespec structure to receive the time
+ * resolution.
+ * @return If the function succeeds, the return value is 0.
+ * If the function fails, the return value is -1,
+ * with errno set to indicate the error.
+ */
+int clock_getres(clockid_t clock_id, struct timespec *res)
+{
+ clockid_t id = clock_id;
+
+ if (id == CLOCK_REALTIME && _pthread_get_system_time_best_as_file_time == GetSystemTimeAsFileTime)
+ id = CLOCK_REALTIME_COARSE; /* GetSystemTimePreciseAsFileTime() not available */
+
+ switch(id) {
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ {
+ LARGE_INTEGER pf;
+
+ if (QueryPerformanceFrequency(&pf) == 0)
+ return lc_set_errno(EINVAL);
+
+ res->tv_sec = 0;
+ res->tv_nsec = (int) ((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
+ if (res->tv_nsec < 1)
+ res->tv_nsec = 1;
+
+ return 0;
+ }
+
+ case CLOCK_REALTIME_COARSE:
+ case CLOCK_PROCESS_CPUTIME_ID:
+ case CLOCK_THREAD_CPUTIME_ID:
+ {
+ DWORD timeAdjustment, timeIncrement;
+ BOOL isTimeAdjustmentDisabled;
+
+ (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled);
+ res->tv_sec = 0;
+ res->tv_nsec = timeIncrement * 100;
+
+ return 0;
+ }
+ default:
+ break;
+ }
+
+ return lc_set_errno(EINVAL);
+}
+
+/**
+ * Get the time of the specified clock clock_id and stores it in the struct
+ * timespec pointed to by tp.
+ * @param clock_id The clock_id argument is the identifier of the particular
+ * clock on which to act. The following clocks are supported:
+ * <pre>
+ * CLOCK_REALTIME System-wide real-time clock. Setting this clock
+ * requires appropriate privileges.
+ * CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
+ * time since some unspecified starting point.
+ * CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
+ * CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
+ * </pre>
+ * @param tp The pointer to a timespec structure to receive the time.
+ * @return If the function succeeds, the return value is 0.
+ * If the function fails, the return value is -1,
+ * with errno set to indicate the error.
+ */
+int clock_gettime(clockid_t clock_id, struct timespec *tp)
+{
+ unsigned __int64 t;
+ LARGE_INTEGER pf, pc;
+ union {
+ unsigned __int64 u64;
+ FILETIME ft;
+ } ct, et, kt, ut;
+
+ switch(clock_id) {
+ case CLOCK_REALTIME:
+ {
+ _pthread_get_system_time_best_as_file_time(&ct.ft);
+ t = ct.u64 - DELTA_EPOCH_IN_100NS;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ case CLOCK_REALTIME_COARSE:
+ {
+ GetSystemTimeAsFileTime(&ct.ft);
+ t = ct.u64 - DELTA_EPOCH_IN_100NS;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ case CLOCK_MONOTONIC:
+ {
+ if (QueryPerformanceFrequency(&pf) == 0)
+ return lc_set_errno(EINVAL);
+
+ if (QueryPerformanceCounter(&pc) == 0)
+ return lc_set_errno(EINVAL);
+
+ tp->tv_sec = pc.QuadPart / pf.QuadPart;
+ tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
+ if (tp->tv_nsec >= POW10_9) {
+ tp->tv_sec ++;
+ tp->tv_nsec -= POW10_9;
+ }
+
+ return 0;
+ }
+
+ case CLOCK_PROCESS_CPUTIME_ID:
+ {
+ if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
+ return lc_set_errno(EINVAL);
+ t = kt.u64 + ut.u64;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ case CLOCK_THREAD_CPUTIME_ID:
+ {
+ if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
+ return lc_set_errno(EINVAL);
+ t = kt.u64 + ut.u64;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ return lc_set_errno(EINVAL);
+}
+
+/**
+ * Sleep for the specified time.
+ * @param clock_id This argument should always be CLOCK_REALTIME (0).
+ * @param flags 0 for relative sleep interval, others for absolute waking up.
+ * @param request The desired sleep interval or absolute waking up time.
+ * @param remain The remain amount of time to sleep.
+ * The current implemention just ignore it.
+ * @return If the function succeeds, the return value is 0.
+ * If the function fails, the return value is -1,
+ * with errno set to indicate the error.
+ */
+int clock_nanosleep(clockid_t clock_id, int flags,
+ const struct timespec *request,
+ struct timespec *remain)
+{
+ struct timespec tp;
+
+ if (clock_id != CLOCK_REALTIME)
+ return lc_set_errno(EINVAL);
+
+ if (flags == 0)
+ return nanosleep(request, remain);
+
+ /* TIMER_ABSTIME = 1 */
+ clock_gettime(CLOCK_REALTIME, &tp);
+
+ tp.tv_sec = request->tv_sec - tp.tv_sec;
+ tp.tv_nsec = request->tv_nsec - tp.tv_nsec;
+ if (tp.tv_nsec < 0) {
+ tp.tv_nsec += POW10_9;
+ tp.tv_sec --;
+ }
+
+ return nanosleep(&tp, remain);
+}
+
+/**
+ * Set the time of the specified clock clock_id.
+ * @param clock_id This argument should always be CLOCK_REALTIME (0).
+ * @param tp The requested time.
+ * @return If the function succeeds, the return value is 0.
+ * If the function fails, the return value is -1,
+ * with errno set to indicate the error.
+ */
+int clock_settime(clockid_t clock_id, const struct timespec *tp)
+{
+ SYSTEMTIME st;
+
+ union {
+ unsigned __int64 u64;
+ FILETIME ft;
+ } t;
+
+ if (clock_id != CLOCK_REALTIME)
+ return lc_set_errno(EINVAL);
+
+ t.u64 = tp->tv_sec * (__int64) POW10_7 + tp->tv_nsec / 100 + DELTA_EPOCH_IN_100NS;
+ if (FileTimeToSystemTime(&t.ft, &st) == 0)
+ return lc_set_errno(EINVAL);
+
+ if (SetSystemTime(&st) == 0)
+ return lc_set_errno(EPERM);
+
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/cond.c b/vendor/zgui/libs/winpthreads/src/cond.c
new file mode 100644
index 0000000..813648f
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/cond.c
@@ -0,0 +1,755 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+/*
+ * Posix Condition Variables for Microsoft Windows.
+ * 22-9-2010 Partly based on the ACE framework implementation.
+ */
+#include <windows.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <time.h>
+#include "pthread.h"
+#include "pthread_time.h"
+#include "ref.h"
+#include "cond.h"
+#include "thread.h"
+#include "misc.h"
+#include "winpthread_internal.h"
+
+#include "pthread_compat.h"
+
+int __pthread_shallcancel (void);
+
+static int do_sema_b_wait (HANDLE sema, int nointerrupt, DWORD timeout,CRITICAL_SECTION *cs, LONG *val);
+static int do_sema_b_release(HANDLE sema, LONG count,CRITICAL_SECTION *cs, LONG *val);
+static void cleanup_wait(void *arg);
+
+typedef struct sCondWaitHelper {
+ cond_t *c;
+ pthread_mutex_t *external_mutex;
+ int *r;
+} sCondWaitHelper;
+
+int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout);
+
+#ifdef WINPTHREAD_DBG
+static int print_state = 0;
+static FILE *fo;
+void cond_print_set(int state, FILE *f)
+{
+ if (f) fo = f;
+ if (!fo) fo = stdout;
+ print_state = state;
+}
+
+void cond_print(volatile pthread_cond_t *c, char *txt)
+{
+ if (!print_state) return;
+ cond_t *c_ = (cond_t *)*c;
+ if (c_ == NULL) {
+ fprintf(fo,"C%p %lu %s\n",(void *)*c,GetCurrentThreadId(),txt);
+ } else {
+ fprintf(fo,"C%p %lu V=%0X w=%ld %s\n",
+ (void *)*c,
+ GetCurrentThreadId(),
+ (int)c_->valid,
+ c_->waiters_count_,
+ txt
+ );
+ }
+}
+#endif
+
+static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER;
+
+static int
+cond_static_init (pthread_cond_t *c)
+{
+ int r = 0;
+
+ pthread_spin_lock (&cond_locked);
+ if (c == NULL)
+ r = EINVAL;
+ else if (*c == PTHREAD_COND_INITIALIZER)
+ r = pthread_cond_init (c, NULL);
+ else
+ /* We assume someone was faster ... */
+ r = 0;
+ pthread_spin_unlock (&cond_locked);
+ return r;
+}
+
+int
+pthread_condattr_destroy (pthread_condattr_t *a)
+{
+ if (!a)
+ return EINVAL;
+ *a = 0;
+ return 0;
+}
+
+int
+pthread_condattr_init (pthread_condattr_t *a)
+{
+ if (!a)
+ return EINVAL;
+ *a = 0;
+ return 0;
+}
+
+int
+pthread_condattr_getpshared (const pthread_condattr_t *a, int *s)
+{
+ if (!a || !s)
+ return EINVAL;
+ *s = *a;
+ return 0;
+}
+
+int
+pthread_condattr_getclock (const pthread_condattr_t *a, clockid_t *clock_id)
+{
+ if (!a || !clock_id)
+ return EINVAL;
+ *clock_id = 0;
+ return 0;
+}
+
+int
+pthread_condattr_setclock(pthread_condattr_t *a, clockid_t clock_id)
+{
+ if (!a || clock_id != 0)
+ return EINVAL;
+ return 0;
+}
+
+int
+__pthread_clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *rqtp,
+ struct timespec *rmtp)
+{
+ unsigned long long tick, tick2;
+ unsigned long long delay;
+ DWORD dw;
+
+ if (clock_id != CLOCK_REALTIME
+ && clock_id != CLOCK_MONOTONIC
+ && clock_id != CLOCK_PROCESS_CPUTIME_ID)
+ return EINVAL;
+ if ((flags & TIMER_ABSTIME) != 0)
+ delay = _pthread_rel_time_in_ms (rqtp);
+ else
+ delay = _pthread_time_in_ms_from_timespec (rqtp);
+ do
+ {
+ dw = (DWORD) (delay >= 99999ULL ? 99999ULL : delay);
+ tick = _pthread_time_in_ms ();
+ pthread_delay_np_ms (dw);
+ tick2 = _pthread_time_in_ms ();
+ tick2 -= tick;
+ if (tick2 >= delay)
+ delay = 0;
+ else
+ delay -= tick2;
+ }
+ while (delay != 0ULL);
+ if (rmtp)
+ memset (rmtp, 0, sizeof (*rmtp));
+ return 0;
+}
+
+int
+pthread_condattr_setpshared (pthread_condattr_t *a, int s)
+{
+ if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
+ return EINVAL;
+ if (s == PTHREAD_PROCESS_SHARED)
+ {
+ *a = PTHREAD_PROCESS_PRIVATE;
+ return ENOSYS;
+ }
+ *a = s;
+ return 0;
+}
+
+int
+pthread_cond_init (pthread_cond_t *c, const pthread_condattr_t *a)
+{
+ cond_t *_c;
+ int r = 0;
+
+ if (!c)
+ return EINVAL;
+ if (a && *a == PTHREAD_PROCESS_SHARED)
+ return ENOSYS;
+
+ if ((_c = calloc(1, sizeof(*_c))) == NULL)
+ return ENOMEM;
+
+ _c->valid = DEAD_COND;
+ _c->busy = 0;
+ _c->waiters_count_ = 0;
+ _c->waiters_count_gone_ = 0;
+ _c->waiters_count_unblock_ = 0;
+
+ _c->sema_q = CreateSemaphore (NULL, /* no security */
+ 0, /* initially 0 */
+ 0x7fffffff, /* max count */
+ NULL); /* unnamed */
+ _c->sema_b = CreateSemaphore (NULL, /* no security */
+ 0, /* initially 0 */
+ 0x7fffffff, /* max count */
+ NULL);
+ if (_c->sema_q == NULL || _c->sema_b == NULL) {
+ if (_c->sema_q != NULL)
+ CloseHandle (_c->sema_q);
+ if (_c->sema_b != NULL)
+ CloseHandle (_c->sema_b);
+ free (_c);
+ r = EAGAIN;
+ } else {
+ InitializeCriticalSection(&_c->waiters_count_lock_);
+ InitializeCriticalSection(&_c->waiters_b_lock_);
+ InitializeCriticalSection(&_c->waiters_q_lock_);
+ _c->value_q = 0;
+ _c->value_b = 1;
+ }
+ if (!r)
+ {
+ _c->valid = LIFE_COND;
+ *c = (pthread_cond_t)_c;
+ }
+ else
+ *c = (pthread_cond_t)NULL;
+ return r;
+}
+
+int
+pthread_cond_destroy (pthread_cond_t *c)
+{
+ cond_t *_c;
+ int r;
+ if (!c || !*c)
+ return EINVAL;
+ if (*c == PTHREAD_COND_INITIALIZER)
+ {
+ pthread_spin_lock (&cond_locked);
+ if (*c == PTHREAD_COND_INITIALIZER)
+ {
+ *c = (pthread_cond_t)NULL;
+ r = 0;
+ }
+ else
+ r = EBUSY;
+ pthread_spin_unlock (&cond_locked);
+ return r;
+ }
+ _c = (cond_t *) *c;
+ r = do_sema_b_wait(_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+ if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
+ {
+ do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ return EBUSY;
+ }
+ if (_c->waiters_count_ > _c->waiters_count_gone_)
+ {
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (!r) r = EBUSY;
+ LeaveCriticalSection(&_c->waiters_count_lock_);
+ return r;
+ }
+ *c = (pthread_cond_t)NULL;
+ do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+
+ if (!CloseHandle (_c->sema_q) && !r)
+ r = EINVAL;
+ if (!CloseHandle (_c->sema_b) && !r)
+ r = EINVAL;
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ DeleteCriticalSection(&_c->waiters_count_lock_);
+ DeleteCriticalSection(&_c->waiters_b_lock_);
+ DeleteCriticalSection(&_c->waiters_q_lock_);
+ _c->valid = DEAD_COND;
+ free(_c);
+ return 0;
+}
+
+int
+pthread_cond_signal (pthread_cond_t *c)
+{
+ cond_t *_c;
+ int r;
+
+ if (!c || !*c)
+ return EINVAL;
+ _c = (cond_t *)*c;
+ if (_c == (cond_t *)PTHREAD_COND_INITIALIZER)
+ return 0;
+ else if (_c->valid != (unsigned int)LIFE_COND)
+ return EINVAL;
+
+ EnterCriticalSection (&_c->waiters_count_lock_);
+ /* If there aren't any waiters, then this is a no-op. */
+ if (_c->waiters_count_unblock_ != 0)
+ {
+ if (_c->waiters_count_ == 0)
+ {
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ /* pthread_testcancel(); */
+ return 0;
+ }
+ _c->waiters_count_ -= 1;
+ _c->waiters_count_unblock_ += 1;
+ }
+ else if (_c->waiters_count_ > _c->waiters_count_gone_)
+ {
+ r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ {
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ /* pthread_testcancel(); */
+ return r;
+ }
+ if (_c->waiters_count_gone_ != 0)
+ {
+ _c->waiters_count_ -= _c->waiters_count_gone_;
+ _c->waiters_count_gone_ = 0;
+ }
+ _c->waiters_count_ -= 1;
+ _c->waiters_count_unblock_ = 1;
+ }
+ else
+ {
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ /* pthread_testcancel(); */
+ return 0;
+ }
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ r = do_sema_b_release(_c->sema_q, 1,&_c->waiters_q_lock_,&_c->value_q);
+ /* pthread_testcancel(); */
+ return r;
+}
+
+int
+pthread_cond_broadcast (pthread_cond_t *c)
+{
+ cond_t *_c;
+ int r;
+ int relCnt = 0;
+
+ if (!c || !*c)
+ return EINVAL;
+ _c = (cond_t *)*c;
+ if (_c == (cond_t*)PTHREAD_COND_INITIALIZER)
+ return 0;
+ else if (_c->valid != (unsigned int)LIFE_COND)
+ return EINVAL;
+
+ EnterCriticalSection (&_c->waiters_count_lock_);
+ /* If there aren't any waiters, then this is a no-op. */
+ if (_c->waiters_count_unblock_ != 0)
+ {
+ if (_c->waiters_count_ == 0)
+ {
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ /* pthread_testcancel(); */
+ return 0;
+ }
+ relCnt = _c->waiters_count_;
+ _c->waiters_count_ = 0;
+ _c->waiters_count_unblock_ += relCnt;
+ }
+ else if (_c->waiters_count_ > _c->waiters_count_gone_)
+ {
+ r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ {
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ /* pthread_testcancel(); */
+ return r;
+ }
+ if (_c->waiters_count_gone_ != 0)
+ {
+ _c->waiters_count_ -= _c->waiters_count_gone_;
+ _c->waiters_count_gone_ = 0;
+ }
+ relCnt = _c->waiters_count_;
+ _c->waiters_count_ = 0;
+ _c->waiters_count_unblock_ = relCnt;
+ }
+ else
+ {
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ /* pthread_testcancel(); */
+ return 0;
+ }
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+ r = do_sema_b_release(_c->sema_q, relCnt,&_c->waiters_q_lock_,&_c->value_q);
+ /* pthread_testcancel(); */
+ return r;
+}
+
+int
+pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *external_mutex)
+{
+ sCondWaitHelper ch;
+ cond_t *_c;
+ int r;
+
+ /* pthread_testcancel(); */
+
+ if (!c || *c == (pthread_cond_t)NULL)
+ return EINVAL;
+ _c = (cond_t *)*c;
+ if (*c == PTHREAD_COND_INITIALIZER)
+ {
+ r = cond_static_init(c);
+ if (r != 0 && r != EBUSY)
+ return r;
+ _c = (cond_t *) *c;
+ } else if (_c->valid != (unsigned int)LIFE_COND)
+ return EINVAL;
+
+tryagain:
+ r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+
+ if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
+ {
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+ sched_yield();
+ goto tryagain;
+ }
+
+ _c->waiters_count_++;
+ LeaveCriticalSection(&_c->waiters_count_lock_);
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+
+ ch.c = _c;
+ ch.r = &r;
+ ch.external_mutex = external_mutex;
+
+ pthread_cleanup_push(cleanup_wait, (void *) &ch);
+ r = pthread_mutex_unlock(external_mutex);
+ if (!r)
+ r = do_sema_b_wait (_c->sema_q, 0, INFINITE,&_c->waiters_q_lock_,&_c->value_q);
+
+ pthread_cleanup_pop(1);
+ return r;
+}
+
+static int
+pthread_cond_timedwait_impl (pthread_cond_t *c, pthread_mutex_t *external_mutex, const struct timespec *t, int rel)
+{
+ sCondWaitHelper ch;
+ DWORD dwr;
+ int r;
+ cond_t *_c;
+
+ /* pthread_testcancel(); */
+
+ if (!c || !*c)
+ return EINVAL;
+ _c = (cond_t *)*c;
+ if (_c == (cond_t *)PTHREAD_COND_INITIALIZER)
+ {
+ r = cond_static_init(c);
+ if (r && r != EBUSY)
+ return r;
+ _c = (cond_t *) *c;
+ } else if ((_c)->valid != (unsigned int)LIFE_COND)
+ return EINVAL;
+
+ if (rel == 0)
+ {
+ dwr = dwMilliSecs(_pthread_rel_time_in_ms(t));
+ }
+ else
+ {
+ dwr = dwMilliSecs(_pthread_time_in_ms_from_timespec(t));
+ }
+
+tryagain:
+ r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+
+ if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
+ {
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+ sched_yield();
+ goto tryagain;
+ }
+
+ _c->waiters_count_++;
+ LeaveCriticalSection(&_c->waiters_count_lock_);
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ return r;
+
+ ch.c = _c;
+ ch.r = &r;
+ ch.external_mutex = external_mutex;
+ {
+ pthread_cleanup_push(cleanup_wait, (void *) &ch);
+
+ r = pthread_mutex_unlock(external_mutex);
+ if (!r)
+ r = do_sema_b_wait (_c->sema_q, 0, dwr,&_c->waiters_q_lock_,&_c->value_q);
+
+ pthread_cleanup_pop(1);
+ }
+ return r;
+}
+
+int
+pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *t)
+{
+ return pthread_cond_timedwait_impl(c, m, t, 0);
+}
+
+int
+pthread_cond_timedwait_relative_np(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *t)
+{
+ return pthread_cond_timedwait_impl(c, m, t, 1);
+}
+
+static void
+cleanup_wait (void *arg)
+{
+ int n, r;
+ sCondWaitHelper *ch = (sCondWaitHelper *) arg;
+ cond_t *_c;
+
+ _c = ch->c;
+ EnterCriticalSection (&_c->waiters_count_lock_);
+ n = _c->waiters_count_unblock_;
+ if (n != 0)
+ _c->waiters_count_unblock_ -= 1;
+ else if ((INT_MAX/2) - 1 == _c->waiters_count_gone_)
+ {
+ _c->waiters_count_gone_ += 1;
+ r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ {
+ LeaveCriticalSection(&_c->waiters_count_lock_);
+ ch->r[0] = r;
+ return;
+ }
+ _c->waiters_count_ -= _c->waiters_count_gone_;
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ {
+ LeaveCriticalSection(&_c->waiters_count_lock_);
+ ch->r[0] = r;
+ return;
+ }
+ _c->waiters_count_gone_ = 0;
+ }
+ else
+ _c->waiters_count_gone_ += 1;
+ LeaveCriticalSection (&_c->waiters_count_lock_);
+
+ if (n == 1)
+ {
+ r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
+ if (r != 0)
+ {
+ ch->r[0] = r;
+ return;
+ }
+ }
+ r = pthread_mutex_lock(ch->external_mutex);
+ if (r != 0)
+ ch->r[0] = r;
+}
+
+static int
+do_sema_b_wait (HANDLE sema, int nointerrupt, DWORD timeout,CRITICAL_SECTION *cs, LONG *val)
+{
+ int r;
+ LONG v;
+ EnterCriticalSection(cs);
+ InterlockedDecrement(val);
+ v = val[0];
+ LeaveCriticalSection(cs);
+ if (v >= 0)
+ return 0;
+ r = do_sema_b_wait_intern (sema, nointerrupt, timeout);
+ EnterCriticalSection(cs);
+ if (r != 0)
+ InterlockedIncrement(val);
+ LeaveCriticalSection(cs);
+ return r;
+}
+
+int
+do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout)
+{
+ HANDLE arr[2];
+ DWORD maxH = 1;
+ int r = 0;
+ DWORD res, dt;
+ if (nointerrupt == 1)
+ {
+ res = _pthread_wait_for_single_object(sema, timeout);
+ switch (res) {
+ case WAIT_TIMEOUT:
+ r = ETIMEDOUT;
+ break;
+ case WAIT_ABANDONED:
+ r = EPERM;
+ break;
+ case WAIT_OBJECT_0:
+ break;
+ default:
+ /*We can only return EINVAL though it might not be posix compliant */
+ r = EINVAL;
+ }
+ if (r != 0 && r != EINVAL && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0)
+ r = 0;
+ return r;
+ }
+ arr[0] = sema;
+ arr[1] = (HANDLE) pthread_getevent ();
+ if (arr[1] != NULL) maxH += 1;
+ if (maxH == 2)
+ {
+redo:
+ res = _pthread_wait_for_multiple_objects(maxH, arr, 0, timeout);
+ switch (res) {
+ case WAIT_TIMEOUT:
+ r = ETIMEDOUT;
+ break;
+ case (WAIT_OBJECT_0 + 1):
+ ResetEvent(arr[1]);
+ if (nointerrupt != 2)
+ {
+ pthread_testcancel();
+ return EINVAL;
+ }
+ pthread_testcancel ();
+ goto redo;
+ case WAIT_ABANDONED:
+ r = EPERM;
+ break;
+ case WAIT_OBJECT_0:
+ r = 0;
+ break;
+ default:
+ /*We can only return EINVAL though it might not be posix compliant */
+ r = EINVAL;
+ }
+ if (r != 0 && r != EINVAL && WaitForSingleObject(arr[0], 0) == WAIT_OBJECT_0)
+ r = 0;
+ if (r != 0 && nointerrupt != 2 && __pthread_shallcancel ())
+ return EINVAL;
+ return r;
+ }
+ if (timeout == INFINITE)
+ {
+ do {
+ res = _pthread_wait_for_single_object(sema, 40);
+ switch (res) {
+ case WAIT_TIMEOUT:
+ r = ETIMEDOUT;
+ break;
+ case WAIT_ABANDONED:
+ r = EPERM;
+ break;
+ case WAIT_OBJECT_0:
+ r = 0;
+ break;
+ default:
+ /*We can only return EINVAL though it might not be posix compliant */
+ r = EINVAL;
+ }
+ if (r != 0 && __pthread_shallcancel ())
+ {
+ if (nointerrupt != 2)
+ pthread_testcancel();
+ return EINVAL;
+ }
+ } while (r == ETIMEDOUT);
+ if (r != 0 && r != EINVAL && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0)
+ r = 0;
+ return r;
+ }
+ dt = 20;
+ do {
+ if (dt > timeout) dt = timeout;
+ res = _pthread_wait_for_single_object(sema, dt);
+ switch (res) {
+ case WAIT_TIMEOUT:
+ r = ETIMEDOUT;
+ break;
+ case WAIT_ABANDONED:
+ r = EPERM;
+ break;
+ case WAIT_OBJECT_0:
+ r = 0;
+ break;
+ default:
+ /*We can only return EINVAL though it might not be posix compliant */
+ r = EINVAL;
+ }
+ timeout -= dt;
+ if (timeout != 0 && r != 0 && __pthread_shallcancel ())
+ return EINVAL;
+ } while (r == ETIMEDOUT && timeout != 0);
+ if (r != 0 && r == ETIMEDOUT && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0)
+ r = 0;
+ if (r != 0 && nointerrupt != 2)
+ pthread_testcancel();
+ return r;
+}
+
+static int
+do_sema_b_release(HANDLE sema, LONG count,CRITICAL_SECTION *cs, LONG *val)
+{
+ int wc;
+ EnterCriticalSection(cs);
+ if (((long long) val[0] + (long long) count) > (long long) 0x7fffffffLL)
+ {
+ LeaveCriticalSection(cs);
+ return ERANGE;
+ }
+ wc = -val[0];
+ InterlockedExchangeAdd(val, count);
+ if (wc <= 0 || ReleaseSemaphore(sema, (wc < count ? wc : count), NULL))
+ {
+ LeaveCriticalSection(cs);
+ return 0;
+ }
+ InterlockedExchangeAdd(val, -count);
+ LeaveCriticalSection(cs);
+ return EINVAL;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/cond.h b/vendor/zgui/libs/winpthreads/src/cond.h
new file mode 100644
index 0000000..5e869e9
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/cond.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_PTHREADS_COND_H
+#define WIN_PTHREADS_COND_H
+
+#include <windows.h>
+
+#define CHECK_COND(c) \
+ do { \
+ if (!(c) || !*c || (*c == PTHREAD_COND_INITIALIZER) \
+ || ( ((cond_t *)(*c))->valid != (unsigned int)LIFE_COND ) ) \
+ return EINVAL; \
+ } while (0)
+
+#define LIFE_COND 0xC0BAB1FD
+#define DEAD_COND 0xC0DEADBF
+
+#define STATIC_COND_INITIALIZER(x) ((pthread_cond_t)(x) == ((pthread_cond_t)PTHREAD_COND_INITIALIZER))
+
+typedef struct cond_t cond_t;
+struct cond_t
+{
+ unsigned int valid;
+ int busy;
+ LONG waiters_count_; /* Number of waiting threads. */
+ LONG waiters_count_unblock_; /* Number of waiting threads whitch can be unblocked. */
+ LONG waiters_count_gone_; /* Number of waiters which are gone. */
+ CRITICAL_SECTION waiters_count_lock_; /* Serialize access to <waiters_count_>. */
+ CRITICAL_SECTION waiters_q_lock_; /* Serialize access to sema_q. */
+ LONG value_q;
+ CRITICAL_SECTION waiters_b_lock_; /* Serialize access to sema_b. */
+ LONG value_b;
+ HANDLE sema_q; /* Semaphore used to queue up threads waiting for the condition to
+ become signaled. */
+ HANDLE sema_b; /* Semaphore used to queue up threads waiting for the condition which
+ became signaled. */
+};
+
+void cond_print_set(int state, FILE *f);
+
+void cond_print(volatile pthread_cond_t *c, char *txt);
+
+#endif
diff --git a/vendor/zgui/libs/winpthreads/src/libgcc/dll_math.c b/vendor/zgui/libs/winpthreads/src/libgcc/dll_math.c
new file mode 100644
index 0000000..77bb1fe
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/libgcc/dll_math.c
@@ -0,0 +1,586 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * 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 REGENTS 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.
+ */
+
+#ifndef _LIBKERN_QUAD_H_
+#define _LIBKERN_QUAD_H_
+
+/*
+ * Quad arithmetic.
+ *
+ * This library makes the following assumptions:
+ *
+ * - The type long long (aka quad_t) exists.
+ *
+ * - A quad variable is exactly twice as long as `long'.
+ *
+ * - The machine's arithmetic is two's complement.
+ *
+ * This library can provide 128-bit arithmetic on a machine with 128-bit
+ * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines
+ * with 48-bit longs.
+ */
+/*
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/syslimits.h>
+*/
+
+#include <limits.h>
+typedef long long quad_t;
+typedef unsigned long long u_quad_t;
+typedef unsigned long u_long;
+#define CHAR_BIT __CHAR_BIT__
+
+/*
+ * Define the order of 32-bit words in 64-bit words.
+ * For little endian only.
+ */
+#define _QUAD_HIGHWORD 1
+#define _QUAD_LOWWORD 0
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+ quad_t q; /* as a (signed) quad */
+ quad_t uq; /* as an unsigned quad */
+ long sl[2]; /* as two signed longs */
+ u_long ul[2]; /* as two unsigned longs */
+};
+
+/*
+ * Define high and low longwords.
+ */
+#define H _QUAD_HIGHWORD
+#define L _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT)
+#define LONG_BITS (sizeof(long) * CHAR_BIT)
+#define HALF_BITS (sizeof(long) * CHAR_BIT / 2)
+
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(long)*CHAR_BIT/2).
+ */
+#define HHALF(x) ((x) >> HALF_BITS)
+#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1))
+#define LHUP(x) ((x) << HALF_BITS)
+
+typedef unsigned int qshift_t;
+
+quad_t __ashldi3(quad_t, qshift_t);
+quad_t __ashrdi3(quad_t, qshift_t);
+int __cmpdi2(quad_t a, quad_t b);
+quad_t __divdi3(quad_t a, quad_t b);
+quad_t __lshrdi3(quad_t, qshift_t);
+quad_t __moddi3(quad_t a, quad_t b);
+u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem);
+u_quad_t __udivdi3(u_quad_t a, u_quad_t b);
+u_quad_t __umoddi3(u_quad_t a, u_quad_t b);
+int __ucmpdi2(u_quad_t a, u_quad_t b);
+quad_t __divmoddi4(quad_t a, quad_t b, quad_t *rem);
+u_quad_t __udivmoddi4(u_quad_t a, u_quad_t b, u_quad_t *rem);
+
+#endif /* !_LIBKERN_QUAD_H_ */
+
+#if defined (_X86_) && !defined (__x86_64__)
+/*
+ * Shift a (signed) quad value left (arithmetic shift left).
+ * This is the same as logical shift left!
+ */
+quad_t
+__ashldi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ aa.ul[H] = shift >= QUAD_BITS ? 0 :
+ aa.ul[L] << (shift - LONG_BITS);
+ aa.ul[L] = 0;
+ } else if (shift > 0) {
+ aa.ul[H] = (aa.ul[H] << shift) |
+ (aa.ul[L] >> (LONG_BITS - shift));
+ aa.ul[L] <<= shift;
+ }
+ return (aa.q);
+}
+
+/*
+ * Shift a (signed) quad value right (arithmetic shift right).
+ */
+quad_t
+__ashrdi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ long s;
+
+ /*
+ * Smear bits rightward using the machine's right-shift
+ * method, whether that is sign extension or zero fill,
+ * to get the `sign word' s. Note that shifting by
+ * LONG_BITS is undefined, so we shift (LONG_BITS-1),
+ * then 1 more, to get our answer.
+ */
+ s = (aa.sl[H] >> (LONG_BITS - 1)) >> 1;
+ aa.ul[L] = shift >= QUAD_BITS ? s :
+ aa.sl[H] >> (shift - LONG_BITS);
+ aa.ul[H] = s;
+ } else if (shift > 0) {
+ aa.ul[L] = (aa.ul[L] >> shift) |
+ (aa.ul[H] << (LONG_BITS - shift));
+ aa.sl[H] >>= shift;
+ }
+ return (aa.q);
+}
+
+/*
+ * Return 0, 1, or 2 as a <, =, > b respectively.
+ * Both a and b are considered signed---which means only the high word is
+ * signed.
+ */
+int
+__cmpdi2(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.q = a;
+ bb.q = b;
+ return (aa.sl[H] < bb.sl[H] ? 0 : aa.sl[H] > bb.sl[H] ? 2 :
+ aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
+}
+
+/*
+ * Divide two signed quads.
+ * ??? if -1/2 should produce -1 on this machine, this code is wrong
+ */
+quad_t
+__divdi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, uq;
+ int neg;
+
+ if (a < 0)
+ ua = -(u_quad_t)a, neg = 1;
+ else
+ ua = a, neg = 0;
+ if (b < 0)
+ ub = -(u_quad_t)b, neg ^= 1;
+ else
+ ub = b;
+ uq = __qdivrem(ua, ub, (u_quad_t *)0);
+ return (neg ? -uq : uq);
+}
+
+/*
+ * Shift an (unsigned) quad value right (logical shift right).
+ */
+quad_t
+__lshrdi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ aa.ul[L] = shift >= QUAD_BITS ? 0 :
+ aa.ul[H] >> (shift - LONG_BITS);
+ aa.ul[H] = 0;
+ } else if (shift > 0) {
+ aa.ul[L] = (aa.ul[L] >> shift) |
+ (aa.ul[H] << (LONG_BITS - shift));
+ aa.ul[H] >>= shift;
+ }
+ return (aa.q);
+}
+
+/*
+ * Return remainder after dividing two signed quads.
+ *
+ * XXX
+ * If -1/2 should produce -1 on this machine, this code is wrong.
+ */
+quad_t
+__moddi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, ur;
+ int neg;
+
+ if (a < 0)
+ ua = -(u_quad_t)a, neg = 1;
+ else
+ ua = a, neg = 0;
+ if (b < 0)
+ ub = -(u_quad_t)b;
+ else
+ ub = b;
+ (void)__qdivrem(ua, ub, &ur);
+ return (neg ? -ur : ur);
+}
+
+
+/*
+ * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
+ * section 4.3.1, pp. 257--259.
+ */
+
+#define B (1 << HALF_BITS) /* digit base */
+
+/* Combine two `digits' to make a single two-digit number. */
+#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
+
+/* select a type for digits in base B: use unsigned short if they fit */
+#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff
+typedef unsigned short digit;
+#else
+typedef u_long digit;
+#endif
+
+/*
+ * Shift p[0]..p[len] left `sh' bits, ignoring any bits that
+ * `fall out' the left (there never will be any such anyway).
+ * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
+ */
+static void
+__shl(register digit *p, register int len, register int sh)
+{
+ register int i;
+
+ for (i = 0; i < len; i++)
+ p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
+ p[i] = LHALF(p[i] << sh);
+}
+
+/*
+ * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
+ *
+ * We do this in base 2-sup-HALF_BITS, so that all intermediate products
+ * fit within u_long. As a consequence, the maximum length dividend and
+ * divisor are 4 `digits' in this base (they are shorter if they have
+ * leading zeros).
+ */
+u_quad_t
+__qdivrem(uq, vq, arq)
+ u_quad_t uq, vq, *arq;
+{
+ union uu tmp;
+ digit *u, *v, *q;
+ register digit v1, v2;
+ u_long qhat, rhat, t;
+ int m, n, d, j, i;
+ digit uspace[5], vspace[5], qspace[5];
+
+ /*
+ * Take care of special cases: divide by zero, and u < v.
+ */
+ if (vq == 0) {
+ /* divide by zero. */
+ static volatile const unsigned int zero = 0;
+
+ tmp.ul[H] = tmp.ul[L] = 1 / zero;
+ if (arq)
+ *arq = uq;
+ return (tmp.q);
+ }
+ if (uq < vq) {
+ if (arq)
+ *arq = uq;
+ return (0);
+ }
+ u = &uspace[0];
+ v = &vspace[0];
+ q = &qspace[0];
+
+ /*
+ * Break dividend and divisor into digits in base B, then
+ * count leading zeros to determine m and n. When done, we
+ * will have:
+ * u = (u[1]u[2]...u[m+n]) sub B
+ * v = (v[1]v[2]...v[n]) sub B
+ * v[1] != 0
+ * 1 < n <= 4 (if n = 1, we use a different division algorithm)
+ * m >= 0 (otherwise u < v, which we already checked)
+ * m + n = 4
+ * and thus
+ * m = 4 - n <= 2
+ */
+ tmp.uq = uq;
+ u[0] = 0;
+ u[1] = HHALF(tmp.ul[H]);
+ u[2] = LHALF(tmp.ul[H]);
+ u[3] = HHALF(tmp.ul[L]);
+ u[4] = LHALF(tmp.ul[L]);
+ tmp.uq = vq;
+ v[1] = HHALF(tmp.ul[H]);
+ v[2] = LHALF(tmp.ul[H]);
+ v[3] = HHALF(tmp.ul[L]);
+ v[4] = LHALF(tmp.ul[L]);
+ for (n = 4; v[1] == 0; v++) {
+ if (--n == 1) {
+ u_long rbj; /* r*B+u[j] (not root boy jim) */
+ digit q1, q2, q3, q4;
+
+ /*
+ * Change of plan, per exercise 16.
+ * r = 0;
+ * for j = 1..4:
+ * q[j] = floor((r*B + u[j]) / v),
+ * r = (r*B + u[j]) % v;
+ * We unroll this completely here.
+ */
+ t = v[2]; /* nonzero, by definition */
+ q1 = u[1] / t;
+ rbj = COMBINE(u[1] % t, u[2]);
+ q2 = rbj / t;
+ rbj = COMBINE(rbj % t, u[3]);
+ q3 = rbj / t;
+ rbj = COMBINE(rbj % t, u[4]);
+ q4 = rbj / t;
+ if (arq)
+ *arq = rbj % t;
+ tmp.ul[H] = COMBINE(q1, q2);
+ tmp.ul[L] = COMBINE(q3, q4);
+ return (tmp.q);
+ }
+ }
+
+ /*
+ * By adjusting q once we determine m, we can guarantee that
+ * there is a complete four-digit quotient at &qspace[1] when
+ * we finally stop.
+ */
+ for (m = 4 - n; u[1] == 0; u++)
+ m--;
+ for (i = 4 - m; --i >= 0;)
+ q[i] = 0;
+ q += 4 - m;
+
+ /*
+ * Here we run Program D, translated from MIX to C and acquiring
+ * a few minor changes.
+ *
+ * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
+ */
+ d = 0;
+ for (t = v[1]; t < B / 2; t <<= 1)
+ d++;
+ if (d > 0) {
+ __shl(&u[0], m + n, d); /* u <<= d */
+ __shl(&v[1], n - 1, d); /* v <<= d */
+ }
+ /*
+ * D2: j = 0.
+ */
+ j = 0;
+ v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
+ v2 = v[2]; /* for D3 */
+ do {
+ register digit uj0, uj1, uj2;
+
+ /*
+ * D3: Calculate qhat (\^q, in TeX notation).
+ * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
+ * let rhat = (u[j]*B + u[j+1]) mod v[1].
+ * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
+ * decrement qhat and increase rhat correspondingly.
+ * Note that if rhat >= B, v[2]*qhat < rhat*B.
+ */
+ uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
+ uj1 = u[j + 1]; /* for D3 only */
+ uj2 = u[j + 2]; /* for D3 only */
+ if (uj0 == v1) {
+ qhat = B;
+ rhat = uj1;
+ goto qhat_too_big;
+ } else {
+ u_long nn = COMBINE(uj0, uj1);
+ qhat = nn / v1;
+ rhat = nn % v1;
+ }
+ while (v2 * qhat > COMBINE(rhat, uj2)) {
+ qhat_too_big:
+ qhat--;
+ if ((rhat += v1) >= B)
+ break;
+ }
+ /*
+ * D4: Multiply and subtract.
+ * The variable `t' holds any borrows across the loop.
+ * We split this up so that we do not require v[0] = 0,
+ * and to eliminate a final special case.
+ */
+ for (t = 0, i = n; i > 0; i--) {
+ t = u[i + j] - v[i] * qhat - t;
+ u[i + j] = LHALF(t);
+ t = (B - HHALF(t)) & (B - 1);
+ }
+ t = u[j] - t;
+ u[j] = LHALF(t);
+ /*
+ * D5: test remainder.
+ * There is a borrow if and only if HHALF(t) is nonzero;
+ * in that (rare) case, qhat was too large (by exactly 1).
+ * Fix it by adding v[1..n] to u[j..j+n].
+ */
+ if (HHALF(t)) {
+ qhat--;
+ for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
+ t += u[i + j] + v[i];
+ u[i + j] = LHALF(t);
+ t = HHALF(t);
+ }
+ u[j] = LHALF(u[j] + t);
+ }
+ q[j] = qhat;
+ } while (++j <= m); /* D7: loop on j. */
+
+ /*
+ * If caller wants the remainder, we have to calculate it as
+ * u[m..m+n] >> d (this is at most n digits and thus fits in
+ * u[m+1..m+n], but we may need more source digits).
+ */
+ if (arq) {
+ if (d) {
+ for (i = m + n; i > m; --i)
+ u[i] = (u[i] >> d) |
+ LHALF(u[i - 1] << (HALF_BITS - d));
+ u[i] = 0;
+ }
+ tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
+ tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
+ *arq = tmp.q;
+ }
+
+ tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
+ tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
+ return (tmp.q);
+}
+
+/*
+ * Return 0, 1, or 2 as a <, =, > b respectively.
+ * Neither a nor b are considered signed.
+ */
+int
+__ucmpdi2(a, b)
+ u_quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.uq = a;
+ bb.uq = b;
+ return (aa.ul[H] < bb.ul[H] ? 0 : aa.ul[H] > bb.ul[H] ? 2 :
+ aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
+}
+
+/*
+ * Divide two unsigned quads.
+ */
+u_quad_t
+__udivdi3(a, b)
+ u_quad_t a, b;
+{
+
+ return (__qdivrem(a, b, (u_quad_t *)0));
+}
+
+/*
+ * Return remainder after dividing two unsigned quads.
+ */
+u_quad_t
+__umoddi3(a, b)
+ u_quad_t a, b;
+{
+ u_quad_t r;
+
+ (void)__qdivrem(a, b, &r);
+ return (r);
+}
+
+/*
+ * Divide two signed quads.
+ * This function is new in GCC 7.
+ */
+quad_t
+__divmoddi4(a, b, rem)
+ quad_t a, b, *rem;
+{
+ u_quad_t ua, ub, uq, ur;
+ int negq, negr;
+
+ if (a < 0)
+ ua = -(u_quad_t)a, negq = 1, negr = 1;
+ else
+ ua = a, negq = 0, negr = 0;
+ if (b < 0)
+ ub = -(u_quad_t)b, negq ^= 1;
+ else
+ ub = b;
+ uq = __qdivrem(ua, ub, &ur);
+ if (rem)
+ *rem = (negr ? -ur : ur);
+ return (negq ? -uq : uq);
+}
+
+u_quad_t
+__udivmoddi4(u_quad_t a, u_quad_t b, u_quad_t *rem)
+{
+ return __qdivrem(a, b, rem);
+}
+
+#else
+static int __attribute__((unused)) dummy;
+#endif /*deined (_X86_) && !defined (__x86_64__)*/
+
diff --git a/vendor/zgui/libs/winpthreads/src/misc.c b/vendor/zgui/libs/winpthreads/src/misc.c
new file mode 100644
index 0000000..457bc86
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/misc.c
@@ -0,0 +1,197 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include "pthread.h"
+#include "misc.h"
+
+void (WINAPI *_pthread_get_system_time_best_as_file_time) (LPFILETIME) = NULL;
+static ULONGLONG (WINAPI *_pthread_get_tick_count_64) (VOID);
+
+#if defined(__GNUC__) || defined(__clang__)
+__attribute__((constructor))
+#endif
+static void winpthreads_init(void)
+{
+ HMODULE mod = GetModuleHandleA("kernel32.dll");
+ if (mod)
+ {
+ _pthread_get_tick_count_64 =
+ (ULONGLONG (WINAPI *)(VOID))(void*) GetProcAddress(mod, "GetTickCount64");
+
+ /* <1us precision on Windows 10 */
+ _pthread_get_system_time_best_as_file_time =
+ (void (WINAPI *)(LPFILETIME))(void*) GetProcAddress(mod, "GetSystemTimePreciseAsFileTime");
+ }
+
+ if (!_pthread_get_system_time_best_as_file_time)
+ /* >15ms precision on Windows 10 */
+ _pthread_get_system_time_best_as_file_time = GetSystemTimeAsFileTime;
+}
+
+#if defined(_MSC_VER) && !defined(__clang__)
+/* Force a reference to __xc_t to prevent whole program optimization
+ * from discarding the variable. */
+
+/* On x86, symbols are prefixed with an underscore. */
+# if defined(_M_IX86)
+# pragma comment(linker, "/include:___xc_t")
+# else
+# pragma comment(linker, "/include:__xc_t")
+# endif
+
+#pragma section(".CRT$XCT", long, read)
+__declspec(allocate(".CRT$XCT"))
+extern const _PVFV __xc_t;
+const _PVFV __xc_t = winpthreads_init;
+#endif
+
+unsigned long long _pthread_time_in_ms(void)
+{
+ FILETIME ft;
+
+ GetSystemTimeAsFileTime(&ft);
+ return (((unsigned long long)ft.dwHighDateTime << 32) + ft.dwLowDateTime
+ - 0x19DB1DED53E8000ULL) / 10000ULL;
+}
+
+unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts)
+{
+ unsigned long long t = (unsigned long long) ts->tv_sec * 1000LL;
+ /* The +999999 is here to ensure that the division always rounds up */
+ t += (unsigned long long) (ts->tv_nsec + 999999) / 1000000;
+
+ return t;
+}
+
+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 unsigned long long
+_pthread_get_tick_count (long long *frequency)
+{
+ if (_pthread_get_tick_count_64 != NULL)
+ return _pthread_get_tick_count_64 ();
+
+ LARGE_INTEGER freq, timestamp;
+
+ if (*frequency == 0)
+ {
+ if (QueryPerformanceFrequency (&freq))
+ *frequency = freq.QuadPart;
+ else
+ *frequency = -1;
+ }
+
+ if (*frequency > 0 && QueryPerformanceCounter (&timestamp))
+ return timestamp.QuadPart / (*frequency / 1000);
+
+ /* Fallback */
+ return GetTickCount ();
+}
+
+/* A wrapper around WaitForSingleObject() that ensures that
+ * the wait function does not time out before the time
+ * actually runs out. This is needed because WaitForSingleObject()
+ * might have poor accuracy, returning earlier than expected.
+ * On the other hand, returning a bit *later* than expected
+ * is acceptable in a preemptive multitasking environment.
+ */
+unsigned long
+_pthread_wait_for_single_object (void *handle, unsigned long timeout)
+{
+ DWORD result;
+ unsigned long long start_time, end_time;
+ unsigned long wait_time;
+ long long frequency = 0;
+
+ if (timeout == INFINITE || timeout == 0)
+ return WaitForSingleObject ((HANDLE) handle, (DWORD) timeout);
+
+ start_time = _pthread_get_tick_count (&frequency);
+ end_time = start_time + timeout;
+ wait_time = timeout;
+
+ do
+ {
+ unsigned long long current_time;
+
+ result = WaitForSingleObject ((HANDLE) handle, (DWORD) wait_time);
+ if (result != WAIT_TIMEOUT)
+ break;
+
+ current_time = _pthread_get_tick_count (&frequency);
+ if (current_time >= end_time)
+ break;
+
+ wait_time = (DWORD) (end_time - current_time);
+ } while (TRUE);
+
+ return result;
+}
+
+/* A wrapper around WaitForMultipleObjects() that ensures that
+ * the wait function does not time out before the time
+ * actually runs out. This is needed because WaitForMultipleObjects()
+ * might have poor accuracy, returning earlier than expected.
+ * On the other hand, returning a bit *later* than expected
+ * is acceptable in a preemptive multitasking environment.
+ */
+unsigned long
+_pthread_wait_for_multiple_objects (unsigned long count, void **handles, unsigned int all, unsigned long timeout)
+{
+ DWORD result;
+ unsigned long long start_time, end_time;
+ unsigned long wait_time;
+ long long frequency = 0;
+
+ if (timeout == INFINITE || timeout == 0)
+ return WaitForMultipleObjects ((DWORD) count, (HANDLE *) handles, all, (DWORD) timeout);
+
+ start_time = _pthread_get_tick_count (&frequency);
+ end_time = start_time + timeout;
+ wait_time = timeout;
+
+ do
+ {
+ unsigned long long current_time;
+
+ result = WaitForMultipleObjects ((DWORD) count, (HANDLE *) handles, all, (DWORD) wait_time);
+ if (result != WAIT_TIMEOUT)
+ break;
+
+ current_time = _pthread_get_tick_count (&frequency);
+ if (current_time >= end_time)
+ break;
+
+ wait_time = (DWORD) (end_time - current_time);
+ } while (TRUE);
+
+ return result;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/misc.h b/vendor/zgui/libs/winpthreads/src/misc.h
new file mode 100644
index 0000000..edefb0d
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/misc.h
@@ -0,0 +1,126 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_PTHREADS_MISC_H
+#define WIN_PTHREADS_MISC_H
+
+#include "pthread_compat.h"
+
+#ifndef assert
+
+#ifndef ASSERT_TRACE
+# define ASSERT_TRACE 0
+#else
+# undef ASSERT_TRACE
+# define ASSERT_TRACE 0
+#endif
+
+# define assert(e) \
+ ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
+ "Assertion succeeded: (%s), file %s, line %d\n", \
+ #e, __FILE__, (int) __LINE__), \
+ fflush(stderr) : \
+ 0) : \
+ (fprintf(stderr, "Assertion failed: (%s), file %s, line %d\n", \
+ #e, __FILE__, (int) __LINE__), exit(1), 0))
+
+# define fixme(e) \
+ ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
+ "Assertion succeeded: (%s), file %s, line %d\n", \
+ #e, __FILE__, (int) __LINE__), \
+ fflush(stderr) : \
+ 0) : \
+ (fprintf(stderr, "FIXME: (%s), file %s, line %d\n", \
+ #e, __FILE__, (int) __LINE__), 0, 0))
+
+#endif
+
+#define PTR2INT(x) ((int)(uintptr_t)(x))
+
+#if SIZE_MAX>UINT_MAX
+typedef long long LONGBAG;
+#else
+typedef long LONGBAG;
+#endif
+
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#undef GetHandleInformation
+#define GetHandleInformation(h,f) (1)
+#endif
+
+#define CHECK_HANDLE(h) \
+ do { \
+ DWORD dwFlags; \
+ if (!(h) || ((h) == INVALID_HANDLE_VALUE) || !GetHandleInformation((h), &dwFlags)) \
+ return EINVAL; \
+ } while (0)
+
+#define CHECK_PTR(p) do { if (!(p)) return EINVAL; } while (0)
+
+#define UPD_RESULT(x,r) do { int _r = (x); (r) = (r) ? (r) : _r; } while (0)
+
+#define CHECK_THREAD(t) \
+ do { \
+ CHECK_PTR(t); \
+ CHECK_HANDLE((t)->h); \
+ } while (0)
+
+#define CHECK_OBJECT(o, e) \
+ do { \
+ DWORD dwFlags; \
+ if (!(o)) return e; \
+ if (!((o)->h) || (((o)->h) == INVALID_HANDLE_VALUE) || !GetHandleInformation(((o)->h), &dwFlags)) \
+ return e; \
+ } while (0)
+
+#define VALID(x) if (!(p)) return EINVAL;
+
+/* ms can be 64 bit, solve wrap-around issues: */
+static WINPTHREADS_INLINE unsigned long dwMilliSecs(unsigned long long ms)
+{
+ if (ms >= 0xffffffffULL) return 0xfffffffful;
+ return (unsigned long) ms;
+}
+
+unsigned long long _pthread_time_in_ms(void);
+unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts);
+unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts);
+unsigned long _pthread_wait_for_single_object (void *handle, unsigned long timeout);
+unsigned long _pthread_wait_for_multiple_objects (unsigned long count, void **handles, unsigned int all, unsigned long timeout);
+
+extern void (WINAPI *_pthread_get_system_time_best_as_file_time) (LPFILETIME);
+
+#if defined(__GNUC__) || defined(__clang__)
+#define likely(cond) __builtin_expect((cond) != 0, 1)
+#define unlikely(cond) __builtin_expect((cond) != 0, 0)
+#else
+#define likely(cond) (cond)
+#define unlikely(cond) (cond)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#define UNREACHABLE() __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define UNREACHABLE() __assume(0)
+#endif
+
+#endif
diff --git a/vendor/zgui/libs/winpthreads/src/mutex.c b/vendor/zgui/libs/winpthreads/src/mutex.c
new file mode 100644
index 0000000..866e18d
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/mutex.c
@@ -0,0 +1,381 @@
+/*
+ Copyright (c) 2011, 2014 mingw-w64 project
+ Copyright (c) 2015 Intel Corporation
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include "pthread.h"
+#include "misc.h"
+
+typedef enum {
+ Unlocked, /* Not locked. */
+ Locked, /* Locked but without waiters. */
+ Waiting, /* Locked, may have waiters. */
+} mutex_state_t;
+
+typedef enum {
+ Normal,
+ Errorcheck,
+ Recursive,
+} mutex_type_t;
+
+/* The heap-allocated part of a mutex. */
+typedef struct {
+ mutex_state_t state;
+ mutex_type_t type;
+ HANDLE event; /* Auto-reset event, or NULL if not yet allocated. */
+ unsigned rec_lock; /* For recursive mutexes, the number of times the
+ mutex has been locked in excess by the same thread. */
+ volatile DWORD owner; /* For recursive and error-checking mutexes, the
+ ID of the owning thread if the mutex is locked. */
+} mutex_impl_t;
+
+/* Whether a mutex is still a static initializer (not a pointer to
+ a mutex_impl_t). */
+static bool
+is_static_initializer(pthread_mutex_t m)
+{
+ /* Treat 0 as a static initializer as well (for normal mutexes),
+ to tolerate sloppy code in libgomp. (We should rather fix that code!) */
+ intptr_t v = (intptr_t)m;
+ return v >= -3 && v <= 0;
+/* Should be simple:
+ return (uintptr_t)m >= (uintptr_t)-3; */
+}
+
+/* Create and return the implementation part of a mutex from a static
+ initialiser. Return NULL on out-of-memory error. */
+static WINPTHREADS_ATTRIBUTE((noinline)) mutex_impl_t *
+mutex_impl_init(pthread_mutex_t *m, mutex_impl_t *mi)
+{
+ mutex_impl_t *new_mi = malloc(sizeof(mutex_impl_t));
+ if (new_mi == NULL)
+ return NULL;
+ new_mi->state = Unlocked;
+ new_mi->type = (mi == (void *)PTHREAD_RECURSIVE_MUTEX_INITIALIZER ? Recursive
+ : mi == (void *)PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ? Errorcheck
+ : Normal);
+ new_mi->event = NULL;
+ new_mi->rec_lock = 0;
+ new_mi->owner = (DWORD)-1;
+ if (InterlockedCompareExchangePointer((PVOID volatile *)m, new_mi, mi) == mi) {
+ return new_mi;
+ } else {
+ /* Someone created the struct before us. */
+ free(new_mi);
+ return (mutex_impl_t *)*m;
+ }
+}
+
+/* Return the implementation part of a mutex, creating it if necessary.
+ Return NULL on out-of-memory error. */
+static inline mutex_impl_t *
+mutex_impl(pthread_mutex_t *m)
+{
+ mutex_impl_t *mi = (mutex_impl_t *)*m;
+ if (is_static_initializer((pthread_mutex_t)mi)) {
+ return mutex_impl_init(m, mi);
+ } else {
+ /* mi cannot be null here; avoid a test in the fast path. */
+ if (mi == NULL)
+ UNREACHABLE();
+ return mi;
+ }
+}
+
+/* Lock a mutex. Give up after 'timeout' ms (with ETIMEDOUT),
+ or never if timeout=INFINITE. */
+static inline int
+pthread_mutex_lock_intern (pthread_mutex_t *m, DWORD timeout)
+{
+ mutex_impl_t *mi = mutex_impl(m);
+ if (mi == NULL)
+ return ENOMEM;
+ mutex_state_t old_state = InterlockedExchange((long *)&mi->state, Locked);
+ if (unlikely(old_state != Unlocked)) {
+ /* The mutex is already locked. */
+
+ if (mi->type != Normal) {
+ /* Recursive or Errorcheck */
+ if (mi->owner == GetCurrentThreadId()) {
+ /* FIXME: A recursive mutex should not need two atomic ops when locking
+ recursively. We could rewrite by doing compare-and-swap instead of
+ test-and-set the first time, but it would lead to more code
+ duplication and add a conditional branch to the critical path. */
+ InterlockedCompareExchange((long *)&mi->state, old_state, Locked);
+ if (mi->type == Recursive) {
+ mi->rec_lock++;
+ return 0;
+ } else {
+ /* type == Errorcheck */
+ return EDEADLK;
+ }
+ }
+ }
+
+ /* Make sure there is an event object on which to wait. */
+ if (mi->event == NULL) {
+ /* Make an auto-reset event object. */
+ HANDLE ev = CreateEvent(NULL, false, false, NULL);
+ if (ev == NULL) {
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ return EPERM;
+ default:
+ return ENOMEM; /* Probably accurate enough. */
+ }
+ }
+ if (InterlockedCompareExchangePointer(&mi->event, ev, NULL) != NULL) {
+ /* Someone created the event before us. */
+ CloseHandle(ev);
+ }
+ }
+
+ /* At this point, mi->event is non-NULL. */
+
+ while (InterlockedExchange((long *)&mi->state, Waiting) != Unlocked) {
+ /* For timed locking attempts, it is possible (although unlikely)
+ that we are woken up but someone else grabs the lock before us,
+ and we have to go back to sleep again. In that case, the total
+ wait may be longer than expected. */
+
+ unsigned r = _pthread_wait_for_single_object(mi->event, timeout);
+ switch (r) {
+ case WAIT_TIMEOUT:
+ return ETIMEDOUT;
+ case WAIT_OBJECT_0:
+ break;
+ default:
+ return EINVAL;
+ }
+ }
+ }
+
+ if (mi->type != Normal)
+ mi->owner = GetCurrentThreadId();
+
+ return 0;
+}
+
+int
+pthread_mutex_lock (pthread_mutex_t *m)
+{
+ return pthread_mutex_lock_intern (m, INFINITE);
+}
+
+int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *ts)
+{
+ unsigned long long patience;
+ if (ts != NULL) {
+ unsigned long long end = _pthread_time_in_ms_from_timespec(ts);
+ unsigned long long now = _pthread_time_in_ms();
+ patience = end > now ? end - now : 0;
+ if (patience > 0xffffffff)
+ patience = INFINITE;
+ } else {
+ patience = INFINITE;
+ }
+ return pthread_mutex_lock_intern(m, patience);
+}
+
+int pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ /* Here m might an initialiser of an error-checking or recursive mutex, in
+ which case the behaviour is well-defined, so we can't skip this check. */
+ mutex_impl_t *mi = mutex_impl(m);
+ if (mi == NULL)
+ return ENOMEM;
+
+ if (unlikely(mi->type != Normal)) {
+ if (mi->state == Unlocked)
+ return EINVAL;
+ if (mi->owner != GetCurrentThreadId())
+ return EPERM;
+ if (mi->rec_lock > 0) {
+ mi->rec_lock--;
+ return 0;
+ }
+ mi->owner = (DWORD)-1;
+ }
+ if (unlikely(InterlockedExchange((long *)&mi->state, Unlocked) == Waiting)) {
+ if (!SetEvent(mi->event))
+ return EPERM;
+ }
+ return 0;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t *m)
+{
+ mutex_impl_t *mi = mutex_impl(m);
+ if (mi == NULL)
+ return ENOMEM;
+
+ if (InterlockedCompareExchange((long *)&mi->state, Locked, Unlocked) == Unlocked) {
+ if (mi->type != Normal)
+ mi->owner = GetCurrentThreadId();
+ return 0;
+ } else {
+ if (mi->type == Recursive && mi->owner == GetCurrentThreadId()) {
+ mi->rec_lock++;
+ return 0;
+ }
+ return EBUSY;
+ }
+}
+
+int
+pthread_mutex_init (pthread_mutex_t *m, const pthread_mutexattr_t *a)
+{
+ pthread_mutex_t init = PTHREAD_MUTEX_INITIALIZER;
+ if (a != NULL) {
+ int pshared;
+ if (pthread_mutexattr_getpshared(a, &pshared) == 0
+ && pshared == PTHREAD_PROCESS_SHARED)
+ return ENOSYS;
+
+ int type;
+ if (pthread_mutexattr_gettype(a, &type) == 0) {
+ switch (type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ init = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER;
+ break;
+ case PTHREAD_MUTEX_RECURSIVE:
+ init = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+ break;
+ default:
+ init = PTHREAD_MUTEX_INITIALIZER;
+ break;
+ }
+ }
+ }
+ *m = init;
+ return 0;
+}
+
+int pthread_mutex_destroy (pthread_mutex_t *m)
+{
+ mutex_impl_t *mi = (mutex_impl_t *)*m;
+ if (!is_static_initializer((pthread_mutex_t)mi)) {
+ if (mi->event != NULL)
+ CloseHandle(mi->event);
+ free(mi);
+ /* Sabotage attempts to re-use the mutex before initialising it again. */
+ *m = (pthread_mutex_t)NULL;
+ }
+
+ return 0;
+}
+
+int pthread_mutexattr_init(pthread_mutexattr_t *a)
+{
+ *a = PTHREAD_MUTEX_NORMAL | (PTHREAD_PROCESS_PRIVATE << 3);
+ return 0;
+}
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
+{
+ if (!a)
+ return EINVAL;
+
+ return 0;
+}
+
+int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type)
+{
+ if (!a || !type)
+ return EINVAL;
+
+ *type = *a & 3;
+
+ return 0;
+}
+
+int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
+{
+ if (!a || (type != PTHREAD_MUTEX_NORMAL && type != PTHREAD_MUTEX_RECURSIVE && type != PTHREAD_MUTEX_ERRORCHECK))
+ return EINVAL;
+ *a &= ~3;
+ *a |= type;
+
+ return 0;
+}
+
+int pthread_mutexattr_getpshared(const pthread_mutexattr_t *a, int *type)
+{
+ if (!a || !type)
+ return EINVAL;
+ *type = (*a & 4 ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE);
+
+ return 0;
+}
+
+int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type)
+{
+ int r = 0;
+ if (!a || (type != PTHREAD_PROCESS_SHARED
+ && type != PTHREAD_PROCESS_PRIVATE))
+ return EINVAL;
+ if (type == PTHREAD_PROCESS_SHARED)
+ {
+ type = PTHREAD_PROCESS_PRIVATE;
+ r = ENOSYS;
+ }
+ type = (type == PTHREAD_PROCESS_SHARED ? 4 : 0);
+
+ *a &= ~4;
+ *a |= type;
+
+ return r;
+}
+
+int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & (8 + 16);
+
+ return 0;
+}
+
+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;
+}
+
+int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *a, int * prio)
+{
+ *prio = *a / PTHREAD_PRIO_MULT;
+ return 0;
+}
+
+int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio)
+{
+ *a &= (PTHREAD_PRIO_MULT - 1);
+ *a += prio * PTHREAD_PRIO_MULT;
+
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/nanosleep.c b/vendor/zgui/libs/winpthreads/src/nanosleep.c
new file mode 100644
index 0000000..0cce449
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/nanosleep.c
@@ -0,0 +1,71 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <errno.h>
+#include <time.h>
+#include <windows.h>
+#include "pthread.h"
+#include "pthread_time.h"
+#include "winpthread_internal.h"
+
+#define POW10_3 1000
+#define POW10_4 10000
+#define POW10_6 1000000
+#define POW10_9 1000000000
+#define MAX_SLEEP_IN_MS 4294967294UL
+
+/**
+ * Sleep for the specified time.
+ * @param request The desired amount of time to sleep.
+ * @param remain The remain amount of time to sleep.
+ * @return If the function succeeds, the return value is 0.
+ * If the function fails, the return value is -1,
+ * with errno set to indicate the error.
+ */
+int nanosleep(const struct timespec *request, struct timespec *remain)
+{
+ unsigned long ms, rc = 0;
+ unsigned __int64 u64, want, real;
+
+ union {
+ unsigned __int64 ns100;
+ FILETIME ft;
+ } _start, _end;
+
+ if (request->tv_sec < 0 || request->tv_nsec < 0 || request->tv_nsec >= POW10_9) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (remain != NULL) GetSystemTimeAsFileTime(&_start.ft);
+
+ want = u64 = request->tv_sec * POW10_3 + request->tv_nsec / POW10_6;
+ while (u64 > 0 && rc == 0) {
+ if (u64 >= MAX_SLEEP_IN_MS) ms = MAX_SLEEP_IN_MS;
+ else ms = (unsigned long) u64;
+
+ u64 -= ms;
+ rc = pthread_delay_np_ms(ms);
+ }
+
+ if (rc != 0) { /* WAIT_IO_COMPLETION (192) */
+ if (remain != NULL) {
+ GetSystemTimeAsFileTime(&_end.ft);
+ real = (_end.ns100 - _start.ns100) / POW10_4;
+
+ if (real >= want) u64 = 0;
+ else u64 = want - real;
+
+ remain->tv_sec = u64 / POW10_3;
+ remain->tv_nsec = (long) (u64 % POW10_3) * POW10_6;
+ }
+
+ errno = EINTR;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/ref.c b/vendor/zgui/libs/winpthreads/src/ref.c
new file mode 100644
index 0000000..0344d45
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/ref.c
@@ -0,0 +1,34 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <winternl.h>
+#include <stdio.h>
+#include "pthread.h"
+#include "semaphore.h"
+#include "rwlock.h"
+#include "cond.h"
+#include "barrier.h"
+#include "sem.h"
+#include "ref.h"
+#include "misc.h"
+
diff --git a/vendor/zgui/libs/winpthreads/src/ref.h b/vendor/zgui/libs/winpthreads/src/ref.h
new file mode 100644
index 0000000..5ca6750
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/ref.h
@@ -0,0 +1,29 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_PTHREADS_REF_H
+#define WIN_PTHREADS_REF_H
+#include "pthread.h"
+#include "semaphore.h"
+
+#endif
+
diff --git a/vendor/zgui/libs/winpthreads/src/rwlock.c b/vendor/zgui/libs/winpthreads/src/rwlock.c
new file mode 100644
index 0000000..76669df
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/rwlock.c
@@ -0,0 +1,537 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "pthread.h"
+#include "thread.h"
+#include "ref.h"
+#include "rwlock.h"
+#include "misc.h"
+
+static pthread_spinlock_t rwl_global = PTHREAD_SPINLOCK_INITIALIZER;
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw);
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_unref(volatile pthread_rwlock_t *rwl, int res)
+{
+ pthread_spin_lock(&rwl_global);
+#ifdef WINPTHREAD_DBG
+ assert((((rwlock_t *)*rwl)->valid == LIFE_RWLOCK) && (((rwlock_t *)*rwl)->busy > 0));
+#endif
+ ((rwlock_t *)*rwl)->busy--;
+ pthread_spin_unlock(&rwl_global);
+ return res;
+}
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref(pthread_rwlock_t *rwl, int f )
+{
+ int r = 0;
+ if (STATIC_RWL_INITIALIZER(*rwl)) {
+ r = rwlock_static_init(rwl);
+ if (r != 0 && r != EBUSY)
+ return r;
+ }
+ pthread_spin_lock(&rwl_global);
+
+ if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL;
+ else {
+ ((rwlock_t *)*rwl)->busy ++;
+ }
+
+ pthread_spin_unlock(&rwl_global);
+
+ return r;
+}
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_unlock(pthread_rwlock_t *rwl )
+{
+ int r = 0;
+
+ pthread_spin_lock(&rwl_global);
+
+ if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL;
+ else if (STATIC_RWL_INITIALIZER(*rwl)) r= EPERM;
+ else {
+ ((rwlock_t *)*rwl)->busy ++;
+ }
+
+ pthread_spin_unlock(&rwl_global);
+
+ return r;
+}
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_destroy(pthread_rwlock_t *rwl, pthread_rwlock_t *rDestroy )
+{
+ int r = 0;
+
+ *rDestroy = (pthread_rwlock_t)NULL;
+ pthread_spin_lock(&rwl_global);
+
+ if (!rwl || !*rwl) r = EINVAL;
+ else {
+ rwlock_t *r_ = (rwlock_t *)*rwl;
+ if (STATIC_RWL_INITIALIZER(*rwl)) *rwl = (pthread_rwlock_t)NULL;
+ else if (r_->valid != LIFE_RWLOCK) r = EINVAL;
+ else if (r_->busy) r = EBUSY;
+ else {
+ *rDestroy = *rwl;
+ *rwl = (pthread_rwlock_t)NULL;
+ }
+ }
+
+ pthread_spin_unlock(&rwl_global);
+ return r;
+}
+
+static int rwlock_gain_both_locks(rwlock_t *rwlock)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rwlock->mex);
+ if (ret != 0)
+ return ret;
+ ret = pthread_mutex_lock(&rwlock->mcomplete);
+ if (ret != 0)
+ pthread_mutex_unlock(&rwlock->mex);
+ return ret;
+}
+
+static int rwlock_free_both_locks(rwlock_t *rwlock, int last_fail)
+{
+ int ret, ret2;
+ ret = pthread_mutex_unlock(&rwlock->mcomplete);
+ ret2 = pthread_mutex_unlock(&rwlock->mex);
+ if (last_fail && ret2 != 0)
+ ret = ret2;
+ else if (!last_fail && !ret)
+ ret = ret2;
+ return ret;
+}
+
+#ifdef WINPTHREAD_DBG
+static int print_state = 0;
+void rwl_print_set(int state)
+{
+ print_state = state;
+}
+
+void rwl_print(volatile pthread_rwlock_t *rwl, char *txt)
+{
+ if (!print_state) return;
+ rwlock_t *r = (rwlock_t *)*rwl;
+ if (r == NULL) {
+ printf("RWL%p %lu %s\n",(void *)*rwl,GetCurrentThreadId(),txt);
+ } else {
+ printf("RWL%p %lu V=%0X B=%d r=%ld w=%ld L=%p %s\n",
+ (void *)*rwl,
+ GetCurrentThreadId(),
+ (int)r->valid,
+ (int)r->busy,
+ 0L,0L,NULL,txt);
+ }
+}
+#endif
+
+static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER;
+
+static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw)
+{
+ int r;
+ pthread_spin_lock(&cond_locked);
+ if (*rw != PTHREAD_RWLOCK_INITIALIZER)
+ {
+ pthread_spin_unlock(&cond_locked);
+ return EINVAL;
+ }
+ r = pthread_rwlock_init (rw, NULL);
+ pthread_spin_unlock(&cond_locked);
+
+ return r;
+}
+
+int pthread_rwlock_init (pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr)
+{
+ rwlock_t *rwlock;
+ int r;
+
+ if(!rwlock_)
+ return EINVAL;
+ *rwlock_ = (pthread_rwlock_t)NULL;
+ if ((rwlock = calloc(1, sizeof(*rwlock))) == NULL)
+ return ENOMEM;
+ rwlock->valid = DEAD_RWLOCK;
+
+ rwlock->nex_count = rwlock->nsh_count = rwlock->ncomplete = 0;
+ if ((r = pthread_mutex_init (&rwlock->mex, NULL)) != 0)
+ {
+ free(rwlock);
+ return r;
+ }
+ if ((r = pthread_mutex_init (&rwlock->mcomplete, NULL)) != 0)
+ {
+ pthread_mutex_destroy(&rwlock->mex);
+ free(rwlock);
+ return r;
+ }
+ if ((r = pthread_cond_init (&rwlock->ccomplete, NULL)) != 0)
+ {
+ pthread_mutex_destroy(&rwlock->mex);
+ pthread_mutex_destroy (&rwlock->mcomplete);
+ free(rwlock);
+ return r;
+ }
+ rwlock->valid = LIFE_RWLOCK;
+ *rwlock_ = (pthread_rwlock_t)rwlock;
+ return r;
+}
+
+int pthread_rwlock_destroy (pthread_rwlock_t *rwlock_)
+{
+ rwlock_t *rwlock;
+ pthread_rwlock_t rDestroy;
+ int r, r2;
+
+ pthread_spin_lock(&cond_locked);
+ r = rwl_ref_destroy(rwlock_,&rDestroy);
+ pthread_spin_unlock(&cond_locked);
+
+ if(r) return r;
+ if(!rDestroy) return 0; /* destroyed a (still) static initialized rwl */
+
+ rwlock = (rwlock_t *)rDestroy;
+ r = rwlock_gain_both_locks (rwlock);
+ if (r != 0)
+ {
+ *rwlock_ = rDestroy;
+ return r;
+ }
+ if (rwlock->nsh_count > rwlock->ncomplete || rwlock->nex_count > 0)
+ {
+ *rwlock_ = rDestroy;
+ r = rwlock_free_both_locks(rwlock, 1);
+ if (!r)
+ r = EBUSY;
+ return r;
+ }
+ rwlock->valid = DEAD_RWLOCK;
+ r = rwlock_free_both_locks(rwlock, 0);
+ if (r != 0) { *rwlock_ = rDestroy; return r; }
+
+ r = pthread_cond_destroy(&rwlock->ccomplete);
+ r2 = pthread_mutex_destroy(&rwlock->mex);
+ if (!r) r = r2;
+ r2 = pthread_mutex_destroy(&rwlock->mcomplete);
+ if (!r) r = r2;
+ rwlock->valid = DEAD_RWLOCK;
+ free((void *)rDestroy);
+ return 0;
+}
+
+int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock_)
+{
+ rwlock_t *rwlock;
+ int ret;
+
+ /* pthread_testcancel(); */
+
+ ret = rwl_ref(rwlock_,0);
+ if(ret != 0) return ret;
+
+ rwlock = (rwlock_t *)*rwlock_;
+
+ ret = pthread_mutex_lock(&rwlock->mex);
+ if (ret != 0) return rwl_unref(rwlock_, ret);
+ InterlockedIncrement((long*)&rwlock->nsh_count);
+ if (rwlock->nsh_count == INT_MAX)
+ {
+ ret = pthread_mutex_lock(&rwlock->mcomplete);
+ if (ret != 0)
+ {
+ pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_,ret);
+ }
+ rwlock->nsh_count -= rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ ret = rwlock_free_both_locks(rwlock, 0);
+ return rwl_unref(rwlock_, ret);
+ }
+ ret = pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_, ret);
+}
+
+int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock_, const struct timespec *ts)
+{
+ rwlock_t *rwlock;
+ int ret;
+
+ /* pthread_testcancel(); */
+
+ ret = rwl_ref(rwlock_,0);
+ if(ret != 0) return ret;
+
+ rwlock = (rwlock_t *)*rwlock_;
+ if ((ret = pthread_mutex_timedlock (&rwlock->mex, ts)) != 0)
+ return rwl_unref(rwlock_, ret);
+ InterlockedIncrement(&rwlock->nsh_count);
+ if (rwlock->nsh_count == INT_MAX)
+ {
+ ret = pthread_mutex_timedlock(&rwlock->mcomplete, ts);
+ if (ret != 0)
+ {
+ if (ret == ETIMEDOUT)
+ InterlockedIncrement(&rwlock->ncomplete);
+ pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_, ret);
+ }
+ rwlock->nsh_count -= rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ ret = rwlock_free_both_locks(rwlock, 0);
+ return rwl_unref(rwlock_, ret);
+ }
+ ret = pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_, ret);
+}
+
+int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock_)
+{
+ rwlock_t *rwlock;
+ int ret;
+
+ ret = rwl_ref(rwlock_,RWL_TRY);
+ if(ret != 0) return ret;
+
+ rwlock = (rwlock_t *)*rwlock_;
+ ret = pthread_mutex_trylock(&rwlock->mex);
+ if (ret != 0)
+ return rwl_unref(rwlock_, ret);
+ InterlockedIncrement(&rwlock->nsh_count);
+ if (rwlock->nsh_count == INT_MAX)
+ {
+ ret = pthread_mutex_lock(&rwlock->mcomplete);
+ if (ret != 0)
+ {
+ pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_, ret);
+ }
+ rwlock->nsh_count -= rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ ret = rwlock_free_both_locks(rwlock, 0);
+ return rwl_unref(rwlock_, ret);
+ }
+ ret = pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_,ret);
+}
+
+int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock_)
+{
+ rwlock_t *rwlock;
+ int ret;
+
+ ret = rwl_ref(rwlock_,RWL_TRY);
+ if(ret != 0) return ret;
+
+ rwlock = (rwlock_t *)*rwlock_;
+ ret = pthread_mutex_trylock (&rwlock->mex);
+ if (ret != 0)
+ return rwl_unref(rwlock_, ret);
+ ret = pthread_mutex_trylock(&rwlock->mcomplete);
+ if (ret != 0)
+ {
+ int r1 = pthread_mutex_unlock(&rwlock->mex);
+ if (r1 != 0)
+ ret = r1;
+ return rwl_unref(rwlock_, ret);
+ }
+ if (rwlock->nex_count != 0)
+ return rwl_unref(rwlock_, EBUSY);
+ if (rwlock->ncomplete > 0)
+ {
+ rwlock->nsh_count -= rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ }
+ if (rwlock->nsh_count > 0)
+ {
+ ret = rwlock_free_both_locks(rwlock, 0);
+ if (!ret)
+ ret = EBUSY;
+ return rwl_unref(rwlock_, ret);
+ }
+ rwlock->nex_count = 1;
+ return rwl_unref(rwlock_, 0);
+}
+
+int pthread_rwlock_unlock (pthread_rwlock_t *rwlock_)
+{
+ rwlock_t *rwlock;
+ int ret;
+
+ ret = rwl_ref_unlock(rwlock_);
+ if(ret != 0) return ret;
+
+ rwlock = (rwlock_t *)*rwlock_;
+ if (rwlock->nex_count == 0)
+ {
+ ret = pthread_mutex_lock(&rwlock->mcomplete);
+ if (!ret)
+ {
+ int r1;
+ InterlockedIncrement(&rwlock->ncomplete);
+ if (rwlock->ncomplete == 0)
+ ret = pthread_cond_signal(&rwlock->ccomplete);
+ r1 = pthread_mutex_unlock(&rwlock->mcomplete);
+ if (!ret)
+ ret = r1;
+ }
+ }
+ else
+ {
+ InterlockedDecrement(&rwlock->nex_count);
+ ret = rwlock_free_both_locks(rwlock, 0);
+ }
+ return rwl_unref(rwlock_, ret);
+}
+
+static void st_cancelwrite (void *arg)
+{
+ rwlock_t *rwlock = (rwlock_t *)arg;
+
+ rwlock->nsh_count = - rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ rwlock_free_both_locks(rwlock, 0);
+}
+
+int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock_)
+{
+ rwlock_t *rwlock;
+ int ret;
+
+ /* pthread_testcancel(); */
+ ret = rwl_ref(rwlock_,0);
+ if(ret != 0) return ret;
+
+ rwlock = (rwlock_t *)*rwlock_;
+ ret = rwlock_gain_both_locks(rwlock);
+ if (ret != 0)
+ return rwl_unref(rwlock_,ret);
+
+ if (rwlock->nex_count == 0)
+ {
+ if (rwlock->ncomplete > 0)
+ {
+ rwlock->nsh_count -= rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ }
+ if (rwlock->nsh_count > 0)
+ {
+ rwlock->ncomplete = -rwlock->nsh_count;
+ pthread_cleanup_push(st_cancelwrite, (void *) rwlock);
+ do {
+ ret = pthread_cond_wait(&rwlock->ccomplete, &rwlock->mcomplete);
+ } while (!ret && rwlock->ncomplete < 0);
+
+ pthread_cleanup_pop(!ret ? 0 : 1);
+ if (!ret)
+ rwlock->nsh_count = 0;
+ }
+ }
+ if(!ret)
+ InterlockedIncrement((long*)&rwlock->nex_count);
+ return rwl_unref(rwlock_,ret);
+}
+
+int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock_, const struct timespec *ts)
+{
+ int ret;
+ rwlock_t *rwlock;
+
+ /* pthread_testcancel(); */
+ if (!rwlock_ || !ts)
+ return EINVAL;
+ if ((ret = rwl_ref(rwlock_,0)) != 0)
+ return ret;
+ rwlock = (rwlock_t *)*rwlock_;
+
+ ret = pthread_mutex_timedlock(&rwlock->mex, ts);
+ if (ret != 0)
+ return rwl_unref(rwlock_,ret);
+ ret = pthread_mutex_timedlock (&rwlock->mcomplete, ts);
+ if (ret != 0)
+ {
+ pthread_mutex_unlock(&rwlock->mex);
+ return rwl_unref(rwlock_,ret);
+ }
+ if (rwlock->nex_count == 0)
+ {
+ if (rwlock->ncomplete > 0)
+ {
+ rwlock->nsh_count -= rwlock->ncomplete;
+ rwlock->ncomplete = 0;
+ }
+ if (rwlock->nsh_count > 0)
+ {
+ rwlock->ncomplete = -rwlock->nsh_count;
+ pthread_cleanup_push(st_cancelwrite, (void *) rwlock);
+ do {
+ ret = pthread_cond_timedwait(&rwlock->ccomplete, &rwlock->mcomplete, ts);
+ } while (rwlock->ncomplete < 0 && !ret);
+ pthread_cleanup_pop(!ret ? 0 : 1);
+
+ if (!ret)
+ rwlock->nsh_count = 0;
+ }
+ }
+ if(!ret)
+ InterlockedIncrement((long*)&rwlock->nex_count);
+ return rwl_unref(rwlock_,ret);
+}
+
+int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a)
+{
+ if (!a)
+ return EINVAL;
+ return 0;
+}
+
+int pthread_rwlockattr_init(pthread_rwlockattr_t *a)
+{
+ if (!a)
+ return EINVAL;
+ *a = PTHREAD_PROCESS_PRIVATE;
+ return 0;
+}
+
+int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s)
+{
+ if (!a || !s)
+ return EINVAL;
+ *s = *a;
+ return 0;
+}
+
+int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s)
+{
+ if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
+ return EINVAL;
+ *a = s;
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/rwlock.h b/vendor/zgui/libs/winpthreads/src/rwlock.h
new file mode 100644
index 0000000..2d640fa
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/rwlock.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_PTHREADS_RWLOCK_H
+#define WIN_PTHREADS_RWLOCK_H
+
+#define LIFE_RWLOCK 0xBAB1F0ED
+#define DEAD_RWLOCK 0xDEADB0EF
+
+#define STATIC_RWL_INITIALIZER(x) ((pthread_rwlock_t)(x) == ((pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER))
+
+typedef struct rwlock_t rwlock_t;
+struct rwlock_t {
+ unsigned int valid;
+ int busy;
+ LONG nex_count; /* Exclusive access counter. */
+ LONG nsh_count; /* Shared access counter. */
+ LONG ncomplete; /* Shared completed counter. */
+ pthread_mutex_t mex; /* Exclusive access protection. */
+ pthread_mutex_t mcomplete; /* Shared completed protection. */
+ pthread_cond_t ccomplete; /* Shared access completed queue. */
+};
+
+#define RWL_SET 0x01
+#define RWL_TRY 0x02
+
+void rwl_print(volatile pthread_rwlock_t *rwl, char *txt);
+void rwl_print_set(int state);
+
+#endif
diff --git a/vendor/zgui/libs/winpthreads/src/sched.c b/vendor/zgui/libs/winpthreads/src/sched.c
new file mode 100644
index 0000000..976bcc1
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/sched.c
@@ -0,0 +1,218 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+#include "pthread.h"
+#include "thread.h"
+
+#include "misc.h"
+
+int sched_get_priority_min(int pol)
+{
+ if (pol < SCHED_MIN || pol > SCHED_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return THREAD_PRIORITY_IDLE;
+}
+
+int sched_get_priority_max(int pol)
+{
+ if (pol < SCHED_MIN || pol > SCHED_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return THREAD_PRIORITY_TIME_CRITICAL;
+}
+
+int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *p)
+{
+ int r = 0;
+
+ if (attr == NULL || p == NULL) {
+ return EINVAL;
+ }
+ memcpy(&attr->param, p, sizeof (*p));
+ return r;
+}
+
+int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *p)
+{
+ int r = 0;
+
+ if (attr == NULL || p == NULL) {
+ return EINVAL;
+ }
+ memcpy(p, &attr->param, sizeof (*p));
+ return r;
+}
+
+int pthread_attr_setschedpolicy (pthread_attr_t *attr, int pol)
+{
+ if (!attr || pol < SCHED_MIN || pol > SCHED_MAX)
+ return EINVAL;
+ if (pol != SCHED_OTHER)
+ return ENOTSUP;
+ return 0;
+}
+
+int pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *pol)
+{
+ if (!attr || !pol)
+ return EINVAL;
+ *pol = SCHED_OTHER;
+ return 0;
+}
+
+static int pthread_check(pthread_t t)
+{
+ struct _pthread_v *pv;
+
+ if (!t)
+ return ESRCH;
+ pv = __pth_gpointer_locked (t);
+ if (pv->ended == 0)
+ return 0;
+ CHECK_OBJECT(pv, ESRCH);
+ return 0;
+}
+
+int pthread_getschedparam(pthread_t t, int *pol, struct sched_param *p)
+{
+ int r;
+ //if (!t)
+ // t = pthread_self();
+
+ if ((r = pthread_check(t)) != 0)
+ {
+ return r;
+ }
+
+ if (!p || !pol)
+ {
+ return EINVAL;
+ }
+ *pol = __pth_gpointer_locked (t)->sched_pol;
+ p->sched_priority = __pth_gpointer_locked (t)->sched.sched_priority;
+
+ return 0;
+}
+
+int pthread_setschedparam(pthread_t t, int pol, const struct sched_param *p)
+{
+ struct _pthread_v *pv;
+ int r, pr = 0;
+ //if (!t.p) t = pthread_self();
+
+ if ((r = pthread_check(t)) != 0)
+ return r;
+
+ if (pol < SCHED_MIN || pol > SCHED_MAX || p == NULL)
+ return EINVAL;
+ if (pol != SCHED_OTHER)
+ return ENOTSUP;
+ pr = p->sched_priority;
+ if (pr < sched_get_priority_min(pol) || pr > sched_get_priority_max(pol))
+ return EINVAL;
+
+ /* See msdn: there are actually 7 priorities:
+ THREAD_PRIORITY_IDLE - -15
+ THREAD_PRIORITY_LOWEST -2
+ THREAD_PRIORITY_BELOW_NORMAL -1
+ THREAD_PRIORITY_NORMAL 0
+ THREAD_PRIORITY_ABOVE_NORMAL 1
+ THREAD_PRIORITY_HIGHEST 2
+ THREAD_PRIORITY_TIME_CRITICAL 15
+ */
+ if (pr <= THREAD_PRIORITY_IDLE) {
+ pr = THREAD_PRIORITY_IDLE;
+ } else if (pr <= THREAD_PRIORITY_LOWEST) {
+ pr = THREAD_PRIORITY_LOWEST;
+ } else if (pr >= THREAD_PRIORITY_TIME_CRITICAL) {
+ pr = THREAD_PRIORITY_TIME_CRITICAL;
+ } else if (pr >= THREAD_PRIORITY_HIGHEST) {
+ pr = THREAD_PRIORITY_HIGHEST;
+ }
+ pv = __pth_gpointer_locked (t);
+ if (SetThreadPriority(pv->h, pr)) {
+ pv->sched_pol = pol;
+ pv->sched.sched_priority = p->sched_priority;
+ } else
+ r = EINVAL;
+ return r;
+}
+
+int sched_getscheduler(pid_t pid)
+{
+ if (pid != 0)
+ {
+ HANDLE h = NULL;
+ int selfPid = (int) GetCurrentProcessId ();
+
+ if (pid != (pid_t) selfPid && (h = OpenProcess (PROCESS_QUERY_INFORMATION, 0, (DWORD) pid)) == NULL)
+ {
+ errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
+ return -1;
+ }
+ if (h)
+ CloseHandle (h);
+ }
+ return SCHED_OTHER;
+}
+
+int sched_setscheduler(pid_t pid, int pol, const struct sched_param *param)
+{
+ if (!param)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (pid != 0)
+ {
+ HANDLE h = NULL;
+ int selfPid = (int) GetCurrentProcessId ();
+
+ if (pid != (pid_t) selfPid && (h = OpenProcess (PROCESS_SET_INFORMATION, 0, (DWORD) pid)) == NULL)
+ {
+ errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
+ return -1;
+ }
+ if (h)
+ CloseHandle (h);
+ }
+
+ if (pol != SCHED_OTHER)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+ return SCHED_OTHER;
+}
+
+int sched_yield(void)
+{
+ Sleep(0);
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/sem.c b/vendor/zgui/libs/winpthreads/src/sem.c
new file mode 100644
index 0000000..340ff69
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/sem.c
@@ -0,0 +1,354 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "pthread.h"
+#include "thread.h"
+#include "misc.h"
+#include "semaphore.h"
+#include "sem.h"
+#include "ref.h"
+
+int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout);
+
+static int
+sem_result (int res)
+{
+ if (res != 0) {
+ errno = res;
+ return -1;
+ }
+ return 0;
+}
+
+int
+sem_init (sem_t *sem, int pshared, unsigned int value)
+{
+ _sem_t *sv;
+
+ if (!sem || value > (unsigned int)SEM_VALUE_MAX)
+ return sem_result (EINVAL);
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return sem_result (EPERM);
+
+ if ((sv = (sem_t) calloc (1,sizeof (*sv))) == NULL)
+ return sem_result (ENOMEM);
+
+ sv->value = value;
+ if (pthread_mutex_init (&sv->vlock, NULL) != 0)
+ {
+ free (sv);
+ return sem_result (ENOSPC);
+ }
+ if ((sv->s = CreateSemaphore (NULL, 0, SEM_VALUE_MAX, NULL)) == NULL)
+ {
+ pthread_mutex_destroy (&sv->vlock);
+ free (sv);
+ return sem_result (ENOSPC);
+ }
+
+ sv->valid = LIFE_SEM;
+ *sem = sv;
+ return 0;
+}
+
+int
+sem_destroy (sem_t *sem)
+{
+ int r;
+ _sem_t *sv = NULL;
+
+ if (!sem || (sv = *sem) == NULL)
+ return sem_result (EINVAL);
+ if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
+ return sem_result (r);
+
+#if 0
+ /* We don't wait for destroying a semaphore ...
+ or? */
+ if (sv->value < 0)
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return sem_result (EBUSY);
+ }
+#endif
+
+ if (!CloseHandle (sv->s))
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return sem_result (EINVAL);
+ }
+ *sem = NULL;
+ sv->value = SEM_VALUE_MAX;
+ pthread_mutex_unlock(&sv->vlock);
+ Sleep (0);
+ while (pthread_mutex_destroy (&sv->vlock) == EBUSY)
+ Sleep (0);
+ sv->valid = DEAD_SEM;
+ free (sv);
+ return 0;
+}
+
+static int
+sem_std_enter (sem_t *sem,_sem_t **svp, int do_test)
+{
+ int r;
+ _sem_t *sv;
+
+ if (do_test)
+ pthread_testcancel ();
+ if (!sem)
+ return sem_result (EINVAL);
+ sv = *sem;
+ if (sv == NULL)
+ return sem_result (EINVAL);
+
+ if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
+ return sem_result (r);
+
+ if (*sem == NULL)
+ {
+ pthread_mutex_unlock(&sv->vlock);
+ return sem_result (EINVAL);
+ }
+ *svp = sv;
+ return 0;
+}
+
+int
+sem_trywait (sem_t *sem)
+{
+ _sem_t *sv;
+
+ if (sem_std_enter (sem, &sv, 0) != 0)
+ return -1;
+ if (sv->value <= 0)
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return sem_result (EAGAIN);
+ }
+ sv->value--;
+ pthread_mutex_unlock (&sv->vlock);
+
+ return 0;
+}
+
+struct sSemTimedWait
+{
+ sem_t *p;
+ int *ret;
+};
+
+static void
+clean_wait_sem (void *s)
+{
+ struct sSemTimedWait *p = (struct sSemTimedWait *) s;
+ _sem_t *sv = NULL;
+
+ if (sem_std_enter (p->p, &sv, 0) != 0)
+ return;
+
+ if (WaitForSingleObject (sv->s, 0) != WAIT_OBJECT_0)
+ InterlockedIncrement (&sv->value);
+ else if (p->ret)
+ p->ret[0] = 0;
+ pthread_mutex_unlock (&sv->vlock);
+}
+
+int
+sem_wait (sem_t *sem)
+{
+ long cur_v;
+ int ret = 0;
+ _sem_t *sv;
+ HANDLE semh;
+ struct sSemTimedWait arg;
+
+ if (sem_std_enter (sem, &sv, 1) != 0)
+ return -1;
+
+ arg.ret = &ret;
+ arg.p = sem;
+ InterlockedDecrement (&sv->value);
+ cur_v = sv->value;
+ semh = sv->s;
+ pthread_mutex_unlock (&sv->vlock);
+
+ if (cur_v >= 0)
+ return 0;
+ else
+ {
+ pthread_cleanup_push (clean_wait_sem, (void *) &arg);
+ ret = do_sema_b_wait_intern (semh, 2, INFINITE);
+ pthread_cleanup_pop (ret);
+ if (ret == EINVAL)
+ return 0;
+ }
+
+ if (!ret)
+ return 0;
+
+ return sem_result (ret);
+}
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *t)
+{
+ int cur_v, ret = 0;
+ DWORD dwr;
+ HANDLE semh;
+ _sem_t *sv;
+ struct sSemTimedWait arg;
+
+ if (!t)
+ return sem_wait (sem);
+ dwr = dwMilliSecs(_pthread_rel_time_in_ms (t));
+
+ if (sem_std_enter (sem, &sv, 1) != 0)
+ return -1;
+
+ arg.ret = &ret;
+ arg.p = sem;
+ InterlockedDecrement (&sv->value);
+ cur_v = sv->value;
+ semh = sv->s;
+ pthread_mutex_unlock(&sv->vlock);
+
+ if (cur_v >= 0)
+ return 0;
+ else
+ {
+ pthread_cleanup_push (clean_wait_sem, (void *) &arg);
+ ret = do_sema_b_wait_intern (semh, 2, dwr);
+ pthread_cleanup_pop (ret);
+ if (ret == EINVAL)
+ return 0;
+ }
+
+ if (!ret)
+ return 0;
+ return sem_result (ret);
+}
+
+int
+sem_post (sem_t *sem)
+{
+ _sem_t *sv;
+
+ if (sem_std_enter (sem, &sv, 0) != 0)
+ return -1;
+
+ if (sv->value >= SEM_VALUE_MAX)
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return sem_result (ERANGE);
+ }
+ InterlockedIncrement (&sv->value);
+ if (sv->value > 0 || ReleaseSemaphore (sv->s, 1, NULL))
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return 0;
+ }
+ InterlockedDecrement (&sv->value);
+ pthread_mutex_unlock (&sv->vlock);
+
+ return sem_result (EINVAL);
+}
+
+int
+sem_post_multiple (sem_t *sem, int count)
+{
+ int waiters_count;
+ _sem_t *sv;
+
+ if (count <= 0)
+ return sem_result (EINVAL);
+ if (sem_std_enter (sem, &sv, 0) != 0)
+ return -1;
+
+ if (sv->value > (SEM_VALUE_MAX - count))
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return sem_result (ERANGE);
+ }
+ waiters_count = -sv->value;
+ sv->value += count;
+ /*InterlockedExchangeAdd((long*)&sv->value, (long) count);*/
+ if (waiters_count <= 0
+ || ReleaseSemaphore (sv->s,
+ (waiters_count < count ? waiters_count
+ : count), NULL))
+ {
+ pthread_mutex_unlock(&sv->vlock);
+ return 0;
+ }
+ /*InterlockedExchangeAdd((long*)&sv->value, -((long) count));*/
+ sv->value -= count;
+ pthread_mutex_unlock(&sv->vlock);
+ return sem_result (EINVAL);
+}
+
+sem_t *
+sem_open (const char *name, int oflag, mode_t mode, unsigned int value)
+{
+ sem_result (ENOSYS);
+ return NULL;
+}
+
+int
+sem_close (sem_t *sem)
+{
+ return sem_result (ENOSYS);
+}
+
+int
+sem_unlink (const char *name)
+{
+ return sem_result (ENOSYS);
+}
+
+int
+sem_getvalue (sem_t *sem, int *sval)
+{
+ _sem_t *sv;
+ int r;
+
+ if (!sval)
+ return sem_result (EINVAL);
+
+ if (!sem || (sv = *sem) == NULL)
+ return sem_result (EINVAL);
+
+ if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
+ return sem_result (r);
+ if (*sem == NULL)
+ {
+ pthread_mutex_unlock (&sv->vlock);
+ return sem_result (EINVAL);
+ }
+
+ *sval = (int) sv->value;
+ pthread_mutex_unlock (&sv->vlock);
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/sem.h b/vendor/zgui/libs/winpthreads/src/sem.h
new file mode 100644
index 0000000..3b3ace7
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/sem.h
@@ -0,0 +1,40 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_SEM
+#define WIN_SEM
+
+#include <windows.h>
+
+#define LIFE_SEM 0xBAB1F00D
+#define DEAD_SEM 0xDEADBEEF
+
+typedef struct _sem_t _sem_t;
+struct _sem_t
+{
+ unsigned int valid;
+ HANDLE s;
+ volatile long value;
+ pthread_mutex_t vlock;
+};
+
+#endif /* WIN_SEM */
diff --git a/vendor/zgui/libs/winpthreads/src/spinlock.c b/vendor/zgui/libs/winpthreads/src/spinlock.c
new file mode 100644
index 0000000..224c5a0
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/spinlock.c
@@ -0,0 +1,74 @@
+/*
+ Copyright (c) 2013 mingw-w64 project
+ Copyright (c) 2015 Intel Corporation
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include "pthread.h"
+#include "misc.h"
+
+/* We use the pthread_spinlock_t itself as a lock:
+ -1 is free, 0 is locked.
+ (This is dictated by PTHREAD_SPINLOCK_INITIALIZER, which we can't change
+ without breaking binary compatibility.) */
+typedef intptr_t spinlock_word_t;
+
+int
+pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+ spinlock_word_t *lk = (spinlock_word_t *)lock;
+ *lk = -1;
+ return 0;
+}
+
+
+int
+pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+ return 0;
+}
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+ volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock;
+ while (unlikely(InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0))
+ do {
+ YieldProcessor();
+ } while (*lk == 0);
+ return 0;
+}
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ spinlock_word_t *lk = (spinlock_word_t *)lock;
+ return InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0 ? EBUSY : 0;
+}
+
+
+int
+pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+ volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock;
+ *lk = -1;
+ return 0;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/thread.c b/vendor/zgui/libs/winpthreads/src/thread.c
new file mode 100644
index 0000000..36ee665
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/thread.c
@@ -0,0 +1,1914 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <windows.h>
+#include <strsafe.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <signal.h>
+#include "pthread.h"
+#include "thread.h"
+#include "misc.h"
+#include "winpthread_internal.h"
+
+static _pthread_v *__pthread_self_lite (void);
+
+void (**_pthread_key_dest)(void *) = NULL;
+
+static volatile long _pthread_cancelling;
+static int _pthread_concur;
+
+/* FIXME Will default to zero as needed */
+static pthread_once_t _pthread_tls_once;
+static DWORD _pthread_tls = 0xffffffff;
+
+static pthread_rwlock_t _pthread_key_lock = PTHREAD_RWLOCK_INITIALIZER;
+static unsigned long _pthread_key_max=0L;
+static unsigned long _pthread_key_sch=0L;
+
+static _pthread_v *pthr_root = NULL, *pthr_last = NULL;
+static pthread_mutex_t mtx_pthr_locked = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+
+static __pthread_idlist *idList = NULL;
+static size_t idListCnt = 0;
+static size_t idListMax = 0;
+static pthread_t idListNextId = 0;
+
+#if !defined(_MSC_VER)
+#define USE_VEH_FOR_MSC_SETTHREADNAME
+#endif
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+/* forbidden RemoveVectoredExceptionHandler/AddVectoredExceptionHandler APIs */
+#undef USE_VEH_FOR_MSC_SETTHREADNAME
+#endif
+
+#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
+static void *SetThreadName_VEH_handle = NULL;
+
+static LONG __stdcall
+SetThreadName_VEH (PEXCEPTION_POINTERS ExceptionInfo)
+{
+ if (ExceptionInfo->ExceptionRecord != NULL &&
+ ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SET_THREAD_NAME)
+ return EXCEPTION_CONTINUE_EXECUTION;
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+static PVOID (*AddVectoredExceptionHandlerFuncPtr) (ULONG, PVECTORED_EXCEPTION_HANDLER);
+static ULONG (*RemoveVectoredExceptionHandlerFuncPtr) (PVOID);
+
+static void __attribute__((constructor))
+ctor (void)
+{
+ HMODULE module = GetModuleHandleA("kernel32.dll");
+ if (module) {
+ AddVectoredExceptionHandlerFuncPtr = (__typeof__(AddVectoredExceptionHandlerFuncPtr)) GetProcAddress(module, "AddVectoredExceptionHandler");
+ RemoveVectoredExceptionHandlerFuncPtr = (__typeof__(RemoveVectoredExceptionHandlerFuncPtr)) GetProcAddress(module, "RemoveVectoredExceptionHandler");
+ }
+}
+#endif
+
+typedef struct _THREADNAME_INFO
+{
+ DWORD dwType; /* must be 0x1000 */
+ LPCSTR szName; /* pointer to name (in user addr space) */
+ DWORD dwThreadID; /* thread ID (-1=caller thread) */
+ DWORD dwFlags; /* reserved for future use, must be zero */
+} THREADNAME_INFO;
+
+static void
+SetThreadName (DWORD dwThreadID, LPCSTR szThreadName)
+{
+ THREADNAME_INFO info;
+ DWORD infosize;
+
+ info.dwType = 0x1000;
+ info.szName = szThreadName;
+ info.dwThreadID = dwThreadID;
+ info.dwFlags = 0;
+
+ infosize = sizeof (info) / sizeof (ULONG_PTR);
+
+#if defined(_MSC_VER) && !defined (USE_VEH_FOR_MSC_SETTHREADNAME)
+ __try
+ {
+ RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (ULONG_PTR *)&info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+#else
+ /* Without a debugger we *must* have an exception handler,
+ * otherwise raising an exception will crash the process.
+ */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle == NULL))
+#else
+ if (!IsDebuggerPresent ())
+#endif
+ return;
+
+ RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (ULONG_PTR *) &info);
+#endif
+}
+
+/* Search the list idList for an element with identifier ID. If
+ found, its associated _pthread_v pointer is returned, otherwise
+ NULL.
+ NOTE: This method is not locked. */
+static struct _pthread_v *
+__pthread_get_pointer (pthread_t id)
+{
+ size_t l, r, p;
+ if (!idListCnt)
+ return NULL;
+ if (idListCnt == 1)
+ return (idList[0].id == id ? idList[0].ptr : NULL);
+ l = 0; r = idListCnt - 1;
+ while (l <= r)
+ {
+ p = (l + r) >> 1;
+ if (idList[p].id == id)
+ return idList[p].ptr;
+ else if (idList[p].id > id)
+ {
+ if (p == l)
+ return NULL;
+ r = p - 1;
+ }
+ else
+ {
+ l = p + 1;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+__pth_remove_use_for_key (pthread_key_t key)
+{
+ int i;
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ for (i = 0; i < idListCnt; i++)
+ {
+ if (idList[i].ptr != NULL
+ && idList[i].ptr->keyval != NULL
+ && key < idList[i].ptr->keymax)
+ {
+ idList[i].ptr->keyval[key] = NULL;
+ idList[i].ptr->keyval_set[key] = 0;
+ }
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+}
+
+/* Search the list idList for an element with identifier ID. If
+ found, its associated _pthread_v pointer is returned, otherwise
+ NULL.
+ NOTE: This method uses lock mtx_pthr_locked. */
+struct _pthread_v *
+__pth_gpointer_locked (pthread_t id)
+{
+ struct _pthread_v *ret;
+ if (!id)
+ return NULL;
+ pthread_mutex_lock (&mtx_pthr_locked);
+ ret = __pthread_get_pointer (id);
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return ret;
+}
+
+/* Registers in the list idList an element with _pthread_v pointer
+ and creates and unique identifier ID. If successful created the
+ ID of this element is returned, otherwise on failure zero ID gets
+ returned.
+ NOTE: This method is not locked. */
+static pthread_t
+__pthread_register_pointer (struct _pthread_v *ptr)
+{
+ __pthread_idlist *e;
+ size_t i;
+
+ if (!ptr)
+ return 0;
+ /* Check if a resize of list is necessary. */
+ if (idListCnt >= idListMax)
+ {
+ if (!idListCnt)
+ {
+ e = (__pthread_idlist *) malloc (sizeof (__pthread_idlist) * 16);
+ if (!e)
+ return 0;
+ idListMax = 16;
+ idList = e;
+ }
+ else
+ {
+ e = (__pthread_idlist *) realloc (idList, sizeof (__pthread_idlist) * (idListMax + 16));
+ if (!e)
+ return 0;
+ idListMax += 16;
+ idList = e;
+ }
+ }
+ do
+ {
+ ++idListNextId;
+ /* If two MSB are set we reset to id 1. We need to check here bits
+ to avoid gcc's no-overflow issue on increment. Additionally we
+ need to handle different size of pthread_t on 32-bit/64-bit. */
+ if ((idListNextId & ( ((pthread_t) 1) << ((sizeof (pthread_t) * 8) - 2))) != 0)
+ idListNextId = 1;
+ }
+ while (idListNextId == 0 || __pthread_get_pointer (idListNextId));
+ /* We assume insert at end of list. */
+ i = idListCnt;
+ if (i != 0)
+ {
+ /* Find position we can actual insert sorted. */
+ while (i > 0 && idList[i - 1].id > idListNextId)
+ --i;
+ if (i != idListCnt)
+ memmove (&idList[i + 1], &idList[i], sizeof (__pthread_idlist) * (idListCnt - i));
+ }
+ idList[i].id = idListNextId;
+ idList[i].ptr = ptr;
+ ++idListCnt;
+ return idListNextId;
+}
+
+/* Deregisters in the list idList an element with identifier ID and
+ returns its _pthread_v pointer on success. Otherwise NULL is returned.
+ NOTE: This method is not locked. */
+static struct _pthread_v *
+__pthread_deregister_pointer (pthread_t id)
+{
+ size_t l, r, p;
+ if (!idListCnt)
+ return NULL;
+ l = 0; r = idListCnt - 1;
+ while (l <= r)
+ {
+ p = (l + r) >> 1;
+ if (idList[p].id == id)
+ {
+ struct _pthread_v *ret = idList[p].ptr;
+ p++;
+ if (p < idListCnt)
+ memmove (&idList[p - 1], &idList[p], sizeof (__pthread_idlist) * (idListCnt - p));
+ --idListCnt;
+ /* Is this last element in list then free list. */
+ if (idListCnt == 0)
+ {
+ free (idList);
+ idListCnt = idListMax = 0;
+ }
+ return ret;
+ }
+ else if (idList[p].id > id)
+ {
+ if (p == l)
+ return NULL;
+ r = p - 1;
+ }
+ else
+ {
+ l = p + 1;
+ }
+ }
+ return NULL;
+}
+
+/* Save a _pthread_v element for reuse in pool. */
+static void
+push_pthread_mem (_pthread_v *sv)
+{
+ if (!sv || sv->next != NULL)
+ return;
+ pthread_mutex_lock (&mtx_pthr_locked);
+ if (sv->x != 0)
+ __pthread_deregister_pointer (sv->x);
+ if (sv->keyval)
+ free (sv->keyval);
+ if (sv->keyval_set)
+ free (sv->keyval_set);
+ if (sv->thread_name)
+ free (sv->thread_name);
+ memset (sv, 0, sizeof(struct _pthread_v));
+ if (pthr_last == NULL)
+ pthr_root = pthr_last = sv;
+ else
+ {
+ pthr_last->next = sv;
+ pthr_last = sv;
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+}
+
+/* Get a _pthread_v element from pool, or allocate it.
+ Note the unique identifier is created for the element here, too. */
+static _pthread_v *
+pop_pthread_mem (void)
+{
+ _pthread_v *r = NULL;
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ if ((r = pthr_root) == NULL)
+ {
+ if ((r = (_pthread_v *)calloc (1,sizeof(struct _pthread_v))) != NULL)
+ {
+ r->x = __pthread_register_pointer (r);
+ if (r->x == 0)
+ {
+ free (r);
+ r = NULL;
+ }
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return r;
+ }
+ r->x = __pthread_register_pointer (r);
+ if (r->x == 0)
+ r = NULL;
+ else
+ {
+ if((pthr_root = r->next) == NULL)
+ pthr_last = NULL;
+
+ r->next = NULL;
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return r;
+}
+
+/* Free memory consumed in _pthread_v pointer pool. */
+static void
+free_pthread_mem (void)
+{
+#if 0
+ _pthread_v *t;
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ t = pthr_root;
+ while (t != NULL)
+ {
+ _pthread_v *sv = t;
+ t = t->next;
+ if (sv->x != 0 && sv->ended == 0 && sv->valid != DEAD_THREAD)
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ pthread_cancel (t->x);
+ Sleep (0);
+ pthread_mutex_lock (&mtx_pthr_locked);
+ t = pthr_root;
+ continue;
+ }
+ else if (sv->x != 0 && sv->valid != DEAD_THREAD)
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ Sleep (0);
+ pthread_mutex_lock (&mtx_pthr_locked);
+ continue;
+ }
+ if (sv->x != 0)
+ __pthread_deregister_pointer (sv->x);
+ sv->x = 0;
+ free (sv);
+ pthr_root = t;
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+#endif
+ return;
+}
+
+static void
+replace_spin_keys (pthread_spinlock_t *old, pthread_spinlock_t new)
+{
+ if (old == NULL)
+ return;
+
+ if (EPERM == pthread_spin_destroy (old))
+ {
+#define THREADERR "Error cleaning up spin_keys for thread %lu.\n"
+ char threaderr[sizeof(THREADERR) + 8] = { 0 };
+ snprintf(threaderr, sizeof(threaderr), THREADERR, GetCurrentThreadId());
+#undef THREADERR
+ OutputDebugStringA (threaderr);
+ abort ();
+ }
+
+ *old = new;
+}
+
+/* Hook for TLS-based deregistration/registration of thread. */
+static void WINAPI
+__dyn_tls_pthread (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
+{
+ _pthread_v *t = NULL;
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ if (dwReason == DLL_PROCESS_DETACH)
+ {
+#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
+ if (lpreserved == NULL && SetThreadName_VEH_handle != NULL)
+ {
+ if (RemoveVectoredExceptionHandlerFuncPtr != NULL)
+ RemoveVectoredExceptionHandlerFuncPtr (SetThreadName_VEH_handle);
+ SetThreadName_VEH_handle = NULL;
+ }
+#endif
+ free_pthread_mem ();
+ }
+ else if (dwReason == DLL_PROCESS_ATTACH)
+ {
+#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
+ if (AddVectoredExceptionHandlerFuncPtr != NULL)
+ SetThreadName_VEH_handle = AddVectoredExceptionHandlerFuncPtr (1, &SetThreadName_VEH);
+ else
+ SetThreadName_VEH_handle = NULL;
+ /* Can't do anything on error anyway, check for NULL later */
+#endif
+ }
+ else if (dwReason == DLL_THREAD_DETACH)
+ {
+ if (_pthread_tls != 0xffffffff)
+ t = (_pthread_v *)TlsGetValue(_pthread_tls);
+ if (t && t->thread_noposix != 0)
+ {
+ _pthread_cleanup_dest (t->x);
+ if (t->h != NULL)
+ {
+ CloseHandle (t->h);
+ if (t->evStart)
+ CloseHandle (t->evStart);
+ t->evStart = NULL;
+ t->h = NULL;
+ }
+ pthread_mutex_destroy (&t->p_clock);
+ replace_spin_keys (&t->spin_keys, new_spin_keys);
+ push_pthread_mem (t);
+ t = NULL;
+ TlsSetValue (_pthread_tls, t);
+ }
+ else if (t && t->ended == 0)
+ {
+ if (t->evStart)
+ CloseHandle(t->evStart);
+ t->evStart = NULL;
+ t->ended = 1;
+ _pthread_cleanup_dest (t->x);
+ if ((t->p_state & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED)
+ {
+ t->valid = DEAD_THREAD;
+ if (t->h != NULL)
+ CloseHandle (t->h);
+ t->h = NULL;
+ pthread_mutex_destroy(&t->p_clock);
+ replace_spin_keys (&t->spin_keys, new_spin_keys);
+ push_pthread_mem (t);
+ t = NULL;
+ TlsSetValue (_pthread_tls, t);
+ return;
+ }
+ pthread_mutex_destroy(&t->p_clock);
+ replace_spin_keys (&t->spin_keys, new_spin_keys);
+ }
+ else if (t)
+ {
+ if (t->evStart)
+ CloseHandle (t->evStart);
+ t->evStart = NULL;
+ pthread_mutex_destroy (&t->p_clock);
+ replace_spin_keys (&t->spin_keys, new_spin_keys);
+ }
+ }
+}
+
+/* TLS-runtime section variable. */
+
+#if defined(_MSC_VER)
+/* Force a reference to _tls_used to make the linker create the TLS
+ * directory if it's not already there. (e.g. if __declspec(thread)
+ * is not used).
+ * Force a reference to __xl_f to prevent whole program optimization
+ * from discarding the variable. */
+
+/* On x86, symbols are prefixed with an underscore. */
+# if defined(_M_IX86)
+# pragma comment(linker, "/include:__tls_used")
+# pragma comment(linker, "/include:___xl_f")
+# else
+# pragma comment(linker, "/include:_tls_used")
+# pragma comment(linker, "/include:__xl_f")
+# endif
+
+/* .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK
+ * pointers. Pick an arbitrary location for our callback.
+ *
+ * See VC\...\crt\src\vcruntime\tlssup.cpp for reference. */
+
+# pragma section(".CRT$XLF", long, read)
+#endif
+
+WINPTHREADS_ATTRIBUTE((WINPTHREADS_SECTION(".CRT$XLF")))
+extern const PIMAGE_TLS_CALLBACK __xl_f;
+const PIMAGE_TLS_CALLBACK __xl_f = __dyn_tls_pthread;
+
+
+#ifdef WINPTHREAD_DBG
+static int print_state = 0;
+void thread_print_set (int state)
+{
+ print_state = state;
+}
+
+void
+thread_print (volatile pthread_t t, char *txt)
+{
+ if (!print_state)
+ return;
+ if (!t)
+ printf("T%p %lu %s\n",NULL,GetCurrentThreadId(),txt);
+ else
+ {
+ printf("T%p %lu V=%0X H=%p %s\n",
+ (void *) __pth_gpointer_locked (t),
+ GetCurrentThreadId(),
+ (__pth_gpointer_locked (t))->valid,
+ (__pth_gpointer_locked (t))->h,
+ txt
+ );
+ }
+}
+#endif
+
+/* Internal collect-once structure. */
+typedef struct collect_once_t {
+ pthread_once_t *o;
+ pthread_mutex_t m;
+ int count;
+ struct collect_once_t *next;
+} collect_once_t;
+
+static collect_once_t *once_obj = NULL;
+
+static pthread_spinlock_t once_global = PTHREAD_SPINLOCK_INITIALIZER;
+
+static collect_once_t *
+enterOnceObject (pthread_once_t *o)
+{
+ collect_once_t *c, *p = NULL;
+ pthread_spin_lock (&once_global);
+ c = once_obj;
+ while (c != NULL && c->o != o)
+ {
+ c = (p = c)->next;
+ }
+ if (!c)
+ {
+ c = (collect_once_t *) calloc(1,sizeof(collect_once_t));
+ c->o = o;
+ c->count = 1;
+ if (!p)
+ once_obj = c;
+ else
+ p->next = c;
+ pthread_mutex_init(&c->m, NULL);
+ }
+ else
+ c->count += 1;
+ pthread_spin_unlock (&once_global);
+ return c;
+}
+
+static void
+leaveOnceObject (collect_once_t *c)
+{
+ collect_once_t *h, *p = NULL;
+ if (!c)
+ return;
+ pthread_spin_lock (&once_global);
+ h = once_obj;
+ while (h != NULL && c != h)
+ h = (p = h)->next;
+
+ if (h)
+ {
+ c->count -= 1;
+ if (c->count == 0)
+ {
+ pthread_mutex_destroy(&c->m);
+ if (!p)
+ once_obj = c->next;
+ else
+ p->next = c->next;
+ free (c);
+ }
+ }
+ else
+ fprintf(stderr, "%p not found?!?!\n", (void *) c);
+ pthread_spin_unlock (&once_global);
+}
+
+static void
+_pthread_once_cleanup (void *o)
+{
+ collect_once_t *co = (collect_once_t *) o;
+ pthread_mutex_unlock (&co->m);
+ leaveOnceObject (co);
+}
+
+static int
+_pthread_once_raw (pthread_once_t *o, void (*func)(void))
+{
+ collect_once_t *co;
+ long state = *o;
+
+ CHECK_PTR(o);
+ CHECK_PTR(func);
+
+ if (state == 1)
+ return 0;
+ co = enterOnceObject(o);
+ pthread_mutex_lock(&co->m);
+ if (*o == 0)
+ {
+ func();
+ *o = 1;
+ }
+ else if (*o != 1)
+ fprintf (stderr," once %p is %ld\n", (void *) o, (long) *o);
+ pthread_mutex_unlock(&co->m);
+ leaveOnceObject(co);
+
+ /* Done */
+ return 0;
+}
+
+/* Unimplemented. */
+void *
+pthread_timechange_handler_np(void *dummy)
+{
+ return NULL;
+}
+
+/* Compatibility routine for pthread-win32. It waits for ellapse of
+ interval and additionally checks for possible thread-cancelation. */
+int
+pthread_delay_np (const struct timespec *interval)
+{
+ DWORD to = (!interval ? 0 : dwMilliSecs (_pthread_time_in_ms_from_timespec (interval)));
+ struct _pthread_v *s = __pthread_self_lite ();
+
+ if (!to)
+ {
+ pthread_testcancel ();
+ Sleep (0);
+ pthread_testcancel ();
+ return 0;
+ }
+ pthread_testcancel ();
+ if (s->evStart)
+ _pthread_wait_for_single_object (s->evStart, to);
+ else
+ Sleep (to);
+ pthread_testcancel ();
+ return 0;
+}
+
+int pthread_delay_np_ms (DWORD to);
+
+int
+pthread_delay_np_ms (DWORD to)
+{
+ struct _pthread_v *s = __pthread_self_lite ();
+
+ if (!to)
+ {
+ pthread_testcancel ();
+ Sleep (0);
+ pthread_testcancel ();
+ return 0;
+ }
+ pthread_testcancel ();
+ if (s->evStart)
+ _pthread_wait_for_single_object (s->evStart, to);
+ else
+ Sleep (to);
+ pthread_testcancel ();
+ return 0;
+}
+
+/* Compatibility routine for pthread-win32. It returns the
+ amount of available CPUs on system. */
+int
+pthread_num_processors_np(void)
+{
+ int r = 0;
+ DWORD_PTR ProcessAffinityMask, SystemAffinityMask;
+
+ if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask))
+ {
+ for(; ProcessAffinityMask != 0; ProcessAffinityMask >>= 1)
+ r += (ProcessAffinityMask & 1) != 0;
+ }
+ /* assume at least 1 */
+ return r ? r : 1;
+}
+
+/* Compatiblity routine for pthread-win32. Allows to set amount of used
+ CPUs for process. */
+int
+pthread_set_num_processors_np(int n)
+{
+ DWORD_PTR ProcessAffinityMask, ProcessNewAffinityMask = 0, SystemAffinityMask;
+ int r = 0;
+ /* need at least 1 */
+ n = n ? n : 1;
+ if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask))
+ {
+ for (; ProcessAffinityMask != 0; ProcessAffinityMask >>= 1)
+ {
+ ProcessNewAffinityMask <<= 1;
+ if ((ProcessAffinityMask & 1) != 0 && r < n)
+ {
+ ProcessNewAffinityMask |= 1;
+ r++;
+ }
+ }
+ SetProcessAffinityMask (GetCurrentProcess (),ProcessNewAffinityMask);
+ }
+ return r;
+}
+
+int
+pthread_once (pthread_once_t *o, void (*func)(void))
+{
+ collect_once_t *co;
+ long state = *o;
+
+ CHECK_PTR(o);
+ CHECK_PTR(func);
+
+ if (state == 1)
+ return 0;
+ co = enterOnceObject(o);
+ pthread_mutex_lock(&co->m);
+ if (*o == 0)
+ {
+ pthread_cleanup_push(_pthread_once_cleanup, co);
+ func();
+ pthread_cleanup_pop(0);
+ *o = 1;
+ }
+ else if (*o != 1)
+ fprintf (stderr," once %p is %ld\n", (void *) o, (long) *o);
+ pthread_mutex_unlock(&co->m);
+ leaveOnceObject(co);
+
+ return 0;
+}
+
+int
+pthread_key_create (pthread_key_t *key, void (* dest)(void *))
+{
+ unsigned 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_KEYS_MAX)
+ {
+ pthread_rwlock_unlock(&_pthread_key_lock);
+ return ENOMEM;
+ }
+
+ nmax = _pthread_key_max * 2;
+ if (nmax == 0)
+ nmax = _pthread_key_max + 1;
+ if (nmax > PTHREAD_KEYS_MAX)
+ nmax = PTHREAD_KEYS_MAX;
+
+ /* No spare room anywhere */
+ d = (void (__cdecl **)(void *))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;
+}
+
+int
+pthread_key_delete (pthread_key_t key)
+{
+ if (key >= _pthread_key_max || !_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;
+ /* So now we need to walk the complete list of threads
+ and remove key's reference for it. */
+ __pth_remove_use_for_key (key);
+
+ pthread_rwlock_unlock (&_pthread_key_lock);
+ return 0;
+}
+
+void *
+pthread_getspecific (pthread_key_t key)
+{
+ DWORD lasterr = GetLastError ();
+ void *r;
+ _pthread_v *t = __pthread_self_lite ();
+ pthread_spin_lock (&t->spin_keys);
+ r = (key >= t->keymax || t->keyval_set[key] == 0 ? NULL : t->keyval[key]);
+ pthread_spin_unlock (&t->spin_keys);
+ SetLastError (lasterr);
+ return r;
+}
+
+int
+pthread_setspecific (pthread_key_t key, const void *value)
+{
+ DWORD lasterr = GetLastError ();
+ _pthread_v *t = __pthread_self_lite ();
+
+ pthread_spin_lock (&t->spin_keys);
+
+ if (key >= t->keymax)
+ {
+ int keymax = (key + 1);
+ void **kv;
+ unsigned char *kv_set;
+
+ kv = (void **) realloc (t->keyval, keymax * sizeof (void *));
+
+ if (!kv)
+ {
+ pthread_spin_unlock (&t->spin_keys);
+ return ENOMEM;
+ }
+ kv_set = (unsigned char *) realloc (t->keyval_set, keymax);
+ if (!kv_set)
+ {
+ pthread_spin_unlock (&t->spin_keys);
+ return ENOMEM;
+ }
+
+ /* Clear new region */
+ memset (&kv[t->keymax], 0, (keymax - t->keymax)*sizeof(void *));
+ memset (&kv_set[t->keymax], 0, (keymax - t->keymax));
+
+ t->keyval = kv;
+ t->keyval_set = kv_set;
+ t->keymax = keymax;
+ }
+
+ t->keyval[key] = (void *) value;
+ t->keyval_set[key] = 1;
+ pthread_spin_unlock (&t->spin_keys);
+ SetLastError (lasterr);
+
+ return 0;
+}
+
+int
+pthread_equal (pthread_t t1, pthread_t t2)
+{
+ return (t1 == t2);
+}
+
+void
+pthread_tls_init (void)
+{
+ _pthread_tls = TlsAlloc();
+
+ /* Cannot continue if out of indexes */
+ if (_pthread_tls == TLS_OUT_OF_INDEXES)
+ abort();
+}
+
+void
+_pthread_cleanup_dest (pthread_t t)
+{
+ _pthread_v *tv;
+ unsigned int i, j;
+
+ if (!t)
+ return;
+ tv = __pth_gpointer_locked (t);
+ if (!tv)
+ return;
+
+ for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
+ {
+ int flag = 0;
+
+ pthread_spin_lock (&tv->spin_keys);
+ for (i = 0; i < tv->keymax; i++)
+ {
+ void *val = tv->keyval[i];
+
+ if (tv->keyval_set[i])
+ {
+ pthread_rwlock_rdlock (&_pthread_key_lock);
+ if ((uintptr_t) _pthread_key_dest[i] > 1)
+ {
+ /* Call destructor */
+ tv->keyval[i] = NULL;
+ tv->keyval_set[i] = 0;
+ pthread_spin_unlock (&tv->spin_keys);
+ _pthread_key_dest[i](val);
+ pthread_spin_lock (&tv->spin_keys);
+ flag = 1;
+ }
+ else
+ {
+ tv->keyval[i] = NULL;
+ tv->keyval_set[i] = 0;
+ }
+ pthread_rwlock_unlock(&_pthread_key_lock);
+ }
+ }
+ pthread_spin_unlock (&tv->spin_keys);
+ /* Nothing to do? */
+ if (!flag)
+ return;
+ }
+}
+
+static _pthread_v *
+__pthread_self_lite (void)
+{
+ _pthread_v *t;
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ _pthread_once_raw (&_pthread_tls_once, pthread_tls_init);
+
+ t = (_pthread_v *) TlsGetValue (_pthread_tls);
+ if (t)
+ return t;
+ /* Main thread? */
+ t = (struct _pthread_v *) pop_pthread_mem ();
+
+ /* If cannot initialize main thread, then the only thing we can do is return null pthread_t */
+ if (!__xl_f || !t)
+ return 0;
+
+ t->p_state = PTHREAD_DEFAULT_ATTR /*| PTHREAD_CREATE_DETACHED*/;
+ t->tid = GetCurrentThreadId();
+ t->evStart = CreateEvent (NULL, 1, 0, NULL);
+ t->p_clock = PTHREAD_MUTEX_INITIALIZER;
+ replace_spin_keys (&t->spin_keys, new_spin_keys);
+ t->sched_pol = SCHED_OTHER;
+ t->h = NULL; //GetCurrentThread();
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &t->h, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ abort ();
+ t->sched.sched_priority = GetThreadPriority(t->h);
+ t->ended = 0;
+ t->thread_noposix = 1;
+
+ /* Save for later */
+ if (!TlsSetValue(_pthread_tls, t))
+ abort ();
+ return t;
+}
+
+pthread_t
+pthread_self (void)
+{
+ _pthread_v *t = __pthread_self_lite ();
+
+ if (!t)
+ return 0;
+ return t->x;
+}
+
+/* Internal helper for getting event handle of thread T. */
+void *
+pthread_getevent (void)
+{
+ _pthread_v *t = __pthread_self_lite ();
+ return (!t ? NULL : t->evStart);
+}
+
+/* Internal helper for getting thread handle of thread T. */
+void *
+pthread_gethandle (pthread_t t)
+{
+ struct _pthread_v *tv = __pth_gpointer_locked (t);
+ return (!tv ? NULL : tv->h);
+}
+
+/* Internal helper for getting pointer of clean of current thread. */
+struct _pthread_cleanup **
+pthread_getclean (void)
+{
+ struct _pthread_v *t = __pthread_self_lite ();
+ if (!t) return NULL;
+ return &t->clean;
+}
+
+int
+pthread_get_concurrency (int *val)
+{
+ *val = _pthread_concur;
+ return 0;
+}
+
+int
+pthread_set_concurrency (int val)
+{
+ _pthread_concur = val;
+ return 0;
+}
+
+void
+pthread_exit (void *res)
+{
+ _pthread_v *t = NULL;
+ unsigned rslt = (unsigned) ((intptr_t) res);
+ struct _pthread_v *id = __pthread_self_lite ();
+
+ id->ret_arg = res;
+
+ _pthread_cleanup_dest (id->x);
+ if (id->thread_noposix == 0)
+ longjmp(id->jb, 1);
+
+ /* Make sure we free ourselves if we are detached */
+ if ((t = (_pthread_v *)TlsGetValue(_pthread_tls)) != NULL)
+ {
+ if (!t->h)
+ {
+ t->valid = DEAD_THREAD;
+ if (t->evStart)
+ CloseHandle (t->evStart);
+ t->evStart = NULL;
+ rslt = (unsigned) (size_t) t->ret_arg;
+ push_pthread_mem(t);
+ t = NULL;
+ TlsSetValue (_pthread_tls, t);
+ }
+ else
+ {
+ rslt = (unsigned) (size_t) t->ret_arg;
+ t->ended = 1;
+ if (t->evStart)
+ CloseHandle (t->evStart);
+ t->evStart = NULL;
+ if ((t->p_state & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED)
+ {
+ t->valid = DEAD_THREAD;
+ CloseHandle (t->h);
+ t->h = NULL;
+ push_pthread_mem(t);
+ t = NULL;
+ TlsSetValue(_pthread_tls, t);
+ }
+ }
+ }
+ /* Time to die */
+ _endthreadex(rslt);
+}
+
+void
+_pthread_invoke_cancel (void)
+{
+ _pthread_cleanup *pcup;
+ struct _pthread_v *se = __pthread_self_lite ();
+ se->in_cancel = 1;
+ _pthread_setnobreak (1);
+ InterlockedDecrement(&_pthread_cancelling);
+
+ /* Call cancel queue */
+ for (pcup = se->clean; pcup; pcup = pcup->next)
+ {
+ pcup->func((pthread_once_t *)pcup->arg);
+ }
+
+ _pthread_setnobreak (0);
+ pthread_exit(PTHREAD_CANCELED);
+}
+
+int
+__pthread_shallcancel (void)
+{
+ struct _pthread_v *t;
+ if (!_pthread_cancelling)
+ return 0;
+ t = __pthread_self_lite ();
+ if (t == NULL)
+ return 0;
+ if (t->nobreak <= 0 && t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE))
+ return 1;
+ return 0;
+}
+
+void
+_pthread_setnobreak (int v)
+{
+ struct _pthread_v *t = __pthread_self_lite ();
+ if (t == NULL)
+ return;
+ if (v > 0)
+ InterlockedIncrement ((long*)&t->nobreak);
+ else
+ InterlockedDecrement((long*)&t->nobreak);
+}
+
+void
+pthread_testcancel (void)
+{
+ struct _pthread_v *self = __pthread_self_lite ();
+
+ if (!self || self->in_cancel)
+ return;
+ if (!_pthread_cancelling)
+ return;
+ pthread_mutex_lock (&self->p_clock);
+
+ if (self->cancelled && (self->p_state & PTHREAD_CANCEL_ENABLE) && self->nobreak <= 0)
+ {
+ self->in_cancel = 1;
+ self->p_state &= ~PTHREAD_CANCEL_ENABLE;
+ if (self->evStart)
+ ResetEvent (self->evStart);
+ pthread_mutex_unlock (&self->p_clock);
+ _pthread_invoke_cancel ();
+ }
+ pthread_mutex_unlock (&self->p_clock);
+}
+
+int
+pthread_cancel (pthread_t t)
+{
+ struct _pthread_v *tv = __pth_gpointer_locked (t);
+
+ if (tv == NULL)
+ return ESRCH;
+ CHECK_OBJECT(tv, ESRCH);
+ /*if (tv->ended) return ESRCH;*/
+ pthread_mutex_lock(&tv->p_clock);
+ if (pthread_equal(pthread_self(), t))
+ {
+ if(tv->cancelled)
+ {
+ pthread_mutex_unlock(&tv->p_clock);
+ return (tv->in_cancel ? ESRCH : 0);
+ }
+ tv->cancelled = 1;
+ InterlockedIncrement(&_pthread_cancelling);
+ if(tv->evStart) SetEvent(tv->evStart);
+ if ((tv->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) != 0 && (tv->p_state & PTHREAD_CANCEL_ENABLE) != 0)
+ {
+ tv->p_state &= ~PTHREAD_CANCEL_ENABLE;
+ tv->in_cancel = 1;
+ pthread_mutex_unlock(&tv->p_clock);
+ _pthread_invoke_cancel();
+ }
+ else
+ pthread_mutex_unlock(&tv->p_clock);
+ return 0;
+ }
+
+ if ((tv->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) != 0 && (tv->p_state & PTHREAD_CANCEL_ENABLE) != 0)
+ {
+ /* Dangerous asynchronous cancelling */
+ CONTEXT ctxt;
+
+ if(tv->in_cancel)
+ {
+ pthread_mutex_unlock(&tv->p_clock);
+ return (tv->in_cancel ? ESRCH : 0);
+ }
+ /* Already done? */
+ if(tv->cancelled || tv->in_cancel)
+ {
+ /* ??? pthread_mutex_unlock (&tv->p_clock); */
+ return ESRCH;
+ }
+
+ ctxt.ContextFlags = CONTEXT_CONTROL;
+
+ SuspendThread (tv->h);
+ if (WaitForSingleObject (tv->h, 0) == WAIT_TIMEOUT)
+ {
+ GetThreadContext(tv->h, &ctxt);
+#ifdef _M_X64
+ ctxt.Rip = (uintptr_t) _pthread_invoke_cancel;
+#elif defined(_M_IX86)
+ ctxt.Eip = (uintptr_t) _pthread_invoke_cancel;
+#elif defined(_M_ARM) || defined(_M_ARM64)
+ ctxt.Pc = (uintptr_t) _pthread_invoke_cancel;
+#else
+#error Unsupported architecture
+#endif
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ SetThreadContext (tv->h, &ctxt);
+#endif
+
+ /* Also try deferred Cancelling */
+ tv->cancelled = 1;
+ tv->p_state &= ~PTHREAD_CANCEL_ENABLE;
+ tv->in_cancel = 1;
+
+ /* Notify everyone to look */
+ InterlockedIncrement (&_pthread_cancelling);
+ if (tv->evStart)
+ SetEvent (tv->evStart);
+ pthread_mutex_unlock (&tv->p_clock);
+
+ ResumeThread (tv->h);
+ }
+ }
+ else
+ {
+ if (tv->cancelled == 0)
+ {
+ /* Safe deferred Cancelling */
+ tv->cancelled = 1;
+
+ /* Notify everyone to look */
+ InterlockedIncrement (&_pthread_cancelling);
+ if (tv->evStart)
+ SetEvent (tv->evStart);
+ }
+ else
+ {
+ pthread_mutex_unlock (&tv->p_clock);
+ return (tv->in_cancel ? ESRCH : 0);
+ }
+ }
+ pthread_mutex_unlock (&tv->p_clock);
+ return 0;
+}
+
+/* half-stubbed version as we don't really well support signals */
+int
+pthread_kill (pthread_t t, int sig)
+{
+ struct _pthread_v *tv;
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ tv = __pthread_get_pointer (t);
+ if (!tv || t != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
+ || tv->h == INVALID_HANDLE_VALUE)
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return ESRCH;
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ if (!sig)
+ return 0;
+ if (sig < SIGINT || sig > NSIG)
+ return EINVAL;
+ return pthread_cancel(t);
+}
+
+unsigned
+_pthread_get_state (const pthread_attr_t *attr, unsigned flag)
+{
+ return (attr->p_state & flag);
+}
+
+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;
+}
+
+int
+pthread_attr_init (pthread_attr_t *attr)
+{
+ memset (attr, 0, sizeof (pthread_attr_t));
+ attr->p_state = PTHREAD_DEFAULT_ATTR;
+ attr->stack = NULL;
+ attr->s_size = 0;
+ return 0;
+}
+
+int
+pthread_attr_destroy (pthread_attr_t *attr)
+{
+ /* No need to do anything */
+ memset (attr, 0, sizeof(pthread_attr_t));
+ return 0;
+}
+
+int
+pthread_attr_setdetachstate (pthread_attr_t *a, int flag)
+{
+ return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag);
+}
+
+int
+pthread_attr_getdetachstate (const pthread_attr_t *a, int *flag)
+{
+ *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED);
+ return 0;
+}
+
+int
+pthread_attr_setinheritsched (pthread_attr_t *a, int flag)
+{
+ if (!a || (flag != PTHREAD_INHERIT_SCHED && flag != PTHREAD_EXPLICIT_SCHED))
+ return EINVAL;
+ return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag);
+}
+
+int
+pthread_attr_getinheritsched (const pthread_attr_t *a, int *flag)
+{
+ *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED);
+ return 0;
+}
+
+int
+pthread_attr_setscope (pthread_attr_t *a, int flag)
+{
+ return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag);
+}
+
+int
+pthread_attr_getscope (const pthread_attr_t *a, int *flag)
+{
+ *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM);
+ return 0;
+}
+
+int
+pthread_attr_getstack (const pthread_attr_t *attr, void **stack, size_t *size)
+{
+ *stack = (char *) attr->stack - attr->s_size;
+ *size = attr->s_size;
+ return 0;
+}
+
+int
+pthread_attr_setstack (pthread_attr_t *attr, void *stack, size_t size)
+{
+ attr->s_size = size;
+ attr->stack = (char *) stack + size;
+ return 0;
+}
+
+int
+pthread_attr_getstackaddr (const pthread_attr_t *attr, void **stack)
+{
+ *stack = attr->stack;
+ return 0;
+}
+
+int
+pthread_attr_setstackaddr (pthread_attr_t *attr, void *stack)
+{
+ attr->stack = stack;
+ return 0;
+}
+
+int
+pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
+{
+ *size = attr->s_size;
+ return 0;
+}
+
+int
+pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
+{
+ attr->s_size = size;
+ return 0;
+}
+
+static void
+test_cancel_locked (pthread_t t)
+{
+ struct _pthread_v *tv = __pth_gpointer_locked (t);
+
+ if (!tv || tv->in_cancel || tv->ended != 0 || (tv->p_state & PTHREAD_CANCEL_ENABLE) == 0)
+ return;
+ if ((tv->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)
+ return;
+ if (WaitForSingleObject(tv->evStart, 0) != WAIT_OBJECT_0)
+ return;
+ pthread_mutex_unlock (&tv->p_clock);
+ _pthread_invoke_cancel();
+}
+
+int
+pthread_setcancelstate (int state, int *oldstate)
+{
+ _pthread_v *t = __pthread_self_lite ();
+
+ if (!t || (state & PTHREAD_CANCEL_ENABLE) != state)
+ return EINVAL;
+
+ pthread_mutex_lock (&t->p_clock);
+ if (oldstate)
+ *oldstate = t->p_state & PTHREAD_CANCEL_ENABLE;
+ t->p_state &= ~PTHREAD_CANCEL_ENABLE;
+ t->p_state |= state;
+ test_cancel_locked (t->x);
+ pthread_mutex_unlock (&t->p_clock);
+
+ return 0;
+}
+
+int
+pthread_setcanceltype (int type, int *oldtype)
+{
+ _pthread_v *t = __pthread_self_lite ();
+
+ if (!t || (type & PTHREAD_CANCEL_ASYNCHRONOUS) != type)
+ return EINVAL;
+
+ pthread_mutex_lock (&t->p_clock);
+ if (oldtype)
+ *oldtype = t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS;
+ t->p_state &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ t->p_state |= type;
+ test_cancel_locked (t->x);
+ pthread_mutex_unlock (&t->p_clock);
+
+ return 0;
+}
+
+void _fpreset (void);
+
+#if defined(__i386__)
+/* Align ESP on 16-byte boundaries. */
+# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
+__attribute__((force_align_arg_pointer))
+# endif
+#endif
+unsigned __stdcall
+pthread_create_wrapper (void *args)
+{
+ unsigned rslt = 0;
+ struct _pthread_v *tv = (struct _pthread_v *)args;
+
+ _fpreset();
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ pthread_mutex_lock (&tv->p_clock);
+ _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
+ TlsSetValue(_pthread_tls, tv);
+ tv->tid = GetCurrentThreadId();
+ pthread_mutex_unlock (&tv->p_clock);
+
+
+ if (!setjmp(tv->jb))
+ {
+ intptr_t trslt = (intptr_t) 128;
+ /* Provide to this thread a default exception handler. */
+ #ifdef __SEH__
+ asm ("\t.tl_start:\n");
+ #endif /* Call function and save return value */
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ if (tv->func)
+ trslt = (intptr_t) tv->func(tv->ret_arg);
+ #ifdef __SEH__
+ asm ("\tnop\n\t.tl_end: nop\n"
+#ifdef __arm__
+ "\t.seh_handler __C_specific_handler, %except\n"
+#else
+ "\t.seh_handler __C_specific_handler, @except\n"
+#endif
+ "\t.seh_handlerdata\n"
+ "\t.long 1\n"
+ "\t.rva .tl_start, .tl_end, _gnu_exception_handler ,.tl_end\n"
+ "\t.text"
+ );
+ #endif
+ pthread_mutex_lock (&mtx_pthr_locked);
+ tv->ret_arg = (void*) trslt;
+ /* Clean up destructors */
+ _pthread_cleanup_dest(tv->x);
+ }
+ else
+ pthread_mutex_lock (&mtx_pthr_locked);
+
+ pthread_mutex_lock (&tv->p_clock);
+ rslt = (unsigned) (size_t) tv->ret_arg;
+ /* Make sure we free ourselves if we are detached */
+ if (tv->evStart)
+ CloseHandle (tv->evStart);
+ tv->evStart = NULL;
+ if (!tv->h)
+ {
+ tv->valid = DEAD_THREAD;
+ pthread_mutex_unlock (&tv->p_clock);
+ pthread_mutex_destroy (&tv->p_clock);
+ push_pthread_mem (tv);
+ tv = NULL;
+ TlsSetValue (_pthread_tls, tv);
+ }
+ else
+ {
+ pthread_mutex_unlock (&tv->p_clock);
+ pthread_mutex_destroy (&tv->p_clock);
+ /* Reinitialise p_clock, since there may be attempts at
+ destroying it again in __dyn_tls_thread later on. */
+ tv->p_clock = PTHREAD_MUTEX_INITIALIZER;
+ tv->ended = 1;
+ }
+ while (pthread_mutex_unlock (&mtx_pthr_locked) == 0)
+ Sleep (0);
+ _endthreadex (rslt);
+ return rslt;
+}
+
+int
+pthread_create (pthread_t *th, const pthread_attr_t *attr, void *(* func)(void *), void *arg)
+{
+ HANDLE thrd = NULL;
+ int redo = 0;
+ struct _pthread_v *tv;
+ unsigned int ssize = 0;
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ if (attr && attr->s_size > UINT_MAX)
+ return EINVAL;
+
+ if ((tv = pop_pthread_mem ()) == NULL)
+ return EAGAIN;
+
+ if (th)
+ *th = tv->x;
+
+ /* Save data in pthread_t */
+ tv->ended = 0;
+ tv->ret_arg = arg;
+ tv->func = func;
+ tv->p_state = PTHREAD_DEFAULT_ATTR;
+ tv->h = INVALID_HANDLE_VALUE;
+ /* We retry it here a few times, as events are a limited resource ... */
+ do
+ {
+ tv->evStart = CreateEvent (NULL, 1, 0, NULL);
+ if (tv->evStart != NULL)
+ break;
+ Sleep ((!redo ? 0 : 20));
+ }
+ while (++redo <= 4);
+
+ tv->p_clock = PTHREAD_MUTEX_INITIALIZER;
+ replace_spin_keys (&tv->spin_keys, new_spin_keys);
+ tv->valid = LIFE_THREAD;
+ tv->sched.sched_priority = THREAD_PRIORITY_NORMAL;
+ tv->sched_pol = SCHED_OTHER;
+ if (tv->evStart == NULL)
+ {
+ if (th)
+ memset (th, 0, sizeof (pthread_t));
+ push_pthread_mem (tv);
+ return EAGAIN;
+ }
+
+ if (attr)
+ {
+ int inh = 0;
+ tv->p_state = attr->p_state;
+ ssize = (unsigned int)attr->s_size;
+ pthread_attr_getinheritsched (attr, &inh);
+ if (inh)
+ {
+ tv->sched.sched_priority = __pthread_self_lite ()->sched.sched_priority;
+ }
+ else
+ tv->sched.sched_priority = attr->param.sched_priority;
+ }
+
+ /* Make sure tv->h has value of INVALID_HANDLE_VALUE */
+ _ReadWriteBarrier();
+
+ thrd = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0x4/*CREATE_SUSPEND*/, NULL);
+ if (thrd == INVALID_HANDLE_VALUE)
+ thrd = 0;
+ /* Failed */
+ if (!thrd)
+ {
+ if (tv->evStart)
+ CloseHandle (tv->evStart);
+ pthread_mutex_destroy (&tv->p_clock);
+ replace_spin_keys (&tv->spin_keys, new_spin_keys);
+ tv->evStart = NULL;
+ tv->h = 0;
+ if (th)
+ memset (th, 0, sizeof (pthread_t));
+ push_pthread_mem (tv);
+ return EAGAIN;
+ }
+ {
+ int pr = tv->sched.sched_priority;
+ if (pr <= THREAD_PRIORITY_IDLE) {
+ pr = THREAD_PRIORITY_IDLE;
+ } else if (pr <= THREAD_PRIORITY_LOWEST) {
+ pr = THREAD_PRIORITY_LOWEST;
+ } else if (pr >= THREAD_PRIORITY_TIME_CRITICAL) {
+ pr = THREAD_PRIORITY_TIME_CRITICAL;
+ } else if (pr >= THREAD_PRIORITY_HIGHEST) {
+ pr = THREAD_PRIORITY_HIGHEST;
+ }
+ SetThreadPriority (thrd, pr);
+ }
+ ResetEvent (tv->evStart);
+ if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
+ {
+ tv->h = 0;
+ ResumeThread (thrd);
+ CloseHandle (thrd);
+ }
+ else
+ {
+ tv->h = thrd;
+ ResumeThread (thrd);
+ }
+ Sleep (0);
+ return 0;
+}
+
+int
+pthread_join (pthread_t t, void **res)
+{
+ DWORD dwFlags;
+ struct _pthread_v *tv = __pth_gpointer_locked (t);
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ if (!tv || tv->h == NULL || !GetHandleInformation(tv->h, &dwFlags))
+ return ESRCH;
+ if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
+ return EINVAL;
+ if (pthread_equal(pthread_self(), t))
+ return EDEADLK;
+
+ /* pthread_testcancel (); */
+ if (tv->ended == 0 || (tv->h != NULL && tv->h != INVALID_HANDLE_VALUE))
+ WaitForSingleObject (tv->h, INFINITE);
+ CloseHandle (tv->h);
+ if (tv->evStart)
+ CloseHandle (tv->evStart);
+ tv->evStart = NULL;
+ /* Obtain return value */
+ if (res)
+ *res = tv->ret_arg;
+ pthread_mutex_destroy (&tv->p_clock);
+ replace_spin_keys (&tv->spin_keys, new_spin_keys);
+ push_pthread_mem (tv);
+
+ return 0;
+}
+
+int
+_pthread_tryjoin (pthread_t t, void **res)
+{
+ DWORD dwFlags;
+ struct _pthread_v *tv;
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ tv = __pthread_get_pointer (t);
+
+ if (!tv || tv->h == NULL || !GetHandleInformation(tv->h, &dwFlags))
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return ESRCH;
+ }
+
+ if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return EINVAL;
+ }
+ if (pthread_equal(pthread_self(), t))
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return EDEADLK;
+ }
+ if(tv->ended == 0 && WaitForSingleObject(tv->h, 0))
+ {
+ if (tv->ended == 0)
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ /* pthread_testcancel (); */
+ return EBUSY;
+ }
+ }
+ CloseHandle (tv->h);
+ if (tv->evStart)
+ CloseHandle (tv->evStart);
+ tv->evStart = NULL;
+
+ /* Obtain return value */
+ if (res)
+ *res = tv->ret_arg;
+ pthread_mutex_destroy (&tv->p_clock);
+ replace_spin_keys (&tv->spin_keys, new_spin_keys);
+
+ push_pthread_mem (tv);
+
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ /* pthread_testcancel (); */
+ return 0;
+}
+
+int
+pthread_detach (pthread_t t)
+{
+ int r = 0;
+ DWORD dwFlags;
+ struct _pthread_v *tv = __pth_gpointer_locked (t);
+ HANDLE dw;
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ pthread_mutex_lock (&mtx_pthr_locked);
+ if (!tv || tv->h == NULL || !GetHandleInformation(tv->h, &dwFlags))
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return ESRCH;
+ }
+ if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
+ {
+ pthread_mutex_unlock (&mtx_pthr_locked);
+ return EINVAL;
+ }
+ /* if (tv->ended) r = ESRCH; */
+ dw = tv->h;
+ tv->h = 0;
+ tv->p_state |= PTHREAD_CREATE_DETACHED;
+ _ReadWriteBarrier();
+ if (dw)
+ {
+ CloseHandle (dw);
+ if (tv->ended)
+ {
+ if (tv->evStart)
+ CloseHandle (tv->evStart);
+ tv->evStart = NULL;
+ pthread_mutex_destroy (&tv->p_clock);
+ replace_spin_keys (&tv->spin_keys, new_spin_keys);
+ push_pthread_mem (tv);
+ }
+ }
+ pthread_mutex_unlock (&mtx_pthr_locked);
+
+ return r;
+}
+
+static int dummy_concurrency_level = 0;
+
+int
+pthread_getconcurrency (void)
+{
+ return dummy_concurrency_level;
+}
+
+int
+pthread_setconcurrency (int new_level)
+{
+ dummy_concurrency_level = new_level;
+ return 0;
+}
+
+int
+pthread_setname_np (pthread_t thread, const char *name)
+{
+ struct _pthread_v *tv;
+ char *stored_name;
+
+ if (name == NULL)
+ return EINVAL;
+
+ tv = __pth_gpointer_locked (thread);
+ if (!tv || thread != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
+ || tv->h == INVALID_HANDLE_VALUE)
+ return ESRCH;
+
+ stored_name = strdup (name);
+ if (stored_name == NULL)
+ return ENOMEM;
+
+ if (tv->thread_name != NULL)
+ free (tv->thread_name);
+
+ tv->thread_name = stored_name;
+ SetThreadName (tv->tid, name);
+ return 0;
+}
+
+int
+pthread_getname_np (pthread_t thread, char *name, size_t len)
+{
+ HRESULT result;
+ struct _pthread_v *tv;
+
+ if (name == NULL)
+ return EINVAL;
+
+ tv = __pth_gpointer_locked (thread);
+ if (!tv || thread != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
+ || tv->h == INVALID_HANDLE_VALUE)
+ return ESRCH;
+
+ if (len < 1)
+ return ERANGE;
+
+ if (tv->thread_name == NULL)
+ {
+ name[0] = '\0';
+ return 0;
+ }
+
+ if (strlen (tv->thread_name) >= len)
+ return ERANGE;
+
+ result = StringCchCopyNA (name, len, tv->thread_name, len - 1);
+ if (SUCCEEDED (result))
+ return 0;
+
+ return ERANGE;
+}
diff --git a/vendor/zgui/libs/winpthreads/src/thread.h b/vendor/zgui/libs/winpthreads/src/thread.h
new file mode 100644
index 0000000..5b88226
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/thread.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WIN_PTHREAD_H
+#define WIN_PTHREAD_H
+
+#include <windows.h>
+#include <setjmp.h>
+#include "rwlock.h"
+
+#define LIFE_THREAD 0xBAB1F00D
+#define DEAD_THREAD 0xDEADBEEF
+#define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
+
+typedef struct _pthread_v _pthread_v;
+struct _pthread_v
+{
+ unsigned int valid;
+ void *ret_arg;
+ void *(* func)(void *);
+ _pthread_cleanup *clean;
+ int nobreak;
+ HANDLE h;
+ HANDLE evStart;
+ pthread_mutex_t p_clock;
+ int cancelled : 2;
+ int in_cancel : 2;
+ int thread_noposix : 2;
+ unsigned int p_state;
+ unsigned int keymax;
+ void **keyval;
+ unsigned char *keyval_set;
+ char *thread_name;
+ pthread_spinlock_t spin_keys;
+ DWORD tid;
+ int rwlc;
+ pthread_rwlock_t rwlq[RWLS_PER_THREAD];
+ int sched_pol;
+ int ended;
+ struct sched_param sched;
+ jmp_buf jb;
+ struct _pthread_v *next;
+ pthread_t x; /* Internal posix handle. */
+};
+
+typedef struct __pthread_idlist {
+ struct _pthread_v *ptr;
+ pthread_t id;
+} __pthread_idlist;
+
+int _pthread_tryjoin(pthread_t t, void **res);
+void _pthread_setnobreak(int);
+#ifdef WINPTHREAD_DBG
+void thread_print_set(int state);
+void thread_print(volatile pthread_t t, char *txt);
+#endif
+int __pthread_shallcancel(void);
+struct _pthread_v *WINPTHREAD_API __pth_gpointer_locked (pthread_t id);
+
+#endif
diff --git a/vendor/zgui/libs/winpthreads/src/winpthread_internal.h b/vendor/zgui/libs/winpthreads/src/winpthread_internal.h
new file mode 100644
index 0000000..eb6838c
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/winpthread_internal.h
@@ -0,0 +1,27 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WINPTHREAD_INTERNAL_H
+#define WINPTHREAD_INTERNAL_H
+WINPTHREAD_API struct _pthread_v * __pth_gpointer_locked (pthread_t id);
+int pthread_delay_np_ms (DWORD to);
+#endif /*WINPTHREAD_INTERNAL_H*/
diff --git a/vendor/zgui/libs/winpthreads/src/wpth_ver.h b/vendor/zgui/libs/winpthreads/src/wpth_ver.h
new file mode 100644
index 0000000..1089a61
--- /dev/null
+++ b/vendor/zgui/libs/winpthreads/src/wpth_ver.h
@@ -0,0 +1,29 @@
+/*
+ Copyright (c) 2011-2016 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef __WPTHREADS_VERSION__
+#define __WPTHREADS_VERSION__
+
+#define WPTH_VERSION 1,0,0,0
+#define WPTH_VERSION_STRING "1, 0, 0, 0\0"
+
+#endif