[PATCH 5/9] libs: Import winpthreads from MinGW 8.0.0.
Zebediah Figura
zfigura at codeweavers.com
Mon Nov 29 11:01:18 CST 2021
We need this for PE libvkd3d.
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
As an alternative, we could define a minimal, probably not perfectly conforming,
replacement, which would at least mean adding less code...
configure.ac | 2 +
libs/winpthreads/Makefile.in | 11 +
libs/winpthreads/include/pthread.h | 692 +++++++
libs/winpthreads/include/pthread_compat.h | 86 +
libs/winpthreads/include/pthread_signal.h | 29 +
libs/winpthreads/include/pthread_time.h | 98 +
libs/winpthreads/include/pthread_unistd.h | 192 ++
libs/winpthreads/include/sched.h | 79 +
libs/winpthreads/include/semaphore.h | 81 +
libs/winpthreads/src/barrier.c | 246 +++
libs/winpthreads/src/barrier.h | 49 +
libs/winpthreads/src/clock.c | 240 +++
libs/winpthreads/src/cond.c | 755 +++++++
libs/winpthreads/src/cond.h | 61 +
libs/winpthreads/src/libgcc/dll_dependency.S | 90 +
libs/winpthreads/src/libgcc/dll_math.c | 579 ++++++
libs/winpthreads/src/misc.c | 158 ++
libs/winpthreads/src/misc.h | 114 ++
libs/winpthreads/src/mutex.c | 385 ++++
libs/winpthreads/src/nanosleep.c | 71 +
libs/winpthreads/src/ref.c | 34 +
libs/winpthreads/src/ref.h | 29 +
libs/winpthreads/src/rwlock.c | 533 +++++
libs/winpthreads/src/rwlock.h | 52 +
libs/winpthreads/src/sched.c | 218 ++
libs/winpthreads/src/sem.c | 354 ++++
libs/winpthreads/src/sem.h | 40 +
libs/winpthreads/src/spinlock.c | 81 +
libs/winpthreads/src/thread.c | 1865 ++++++++++++++++++
libs/winpthreads/src/thread.h | 79 +
libs/winpthreads/src/version.rc | 62 +
libs/winpthreads/src/winpthread_internal.h | 27 +
libs/winpthreads/src/wpth_ver.h | 29 +
33 files changed, 7421 insertions(+)
create mode 100644 libs/winpthreads/Makefile.in
create mode 100644 libs/winpthreads/include/pthread.h
create mode 100644 libs/winpthreads/include/pthread_compat.h
create mode 100644 libs/winpthreads/include/pthread_signal.h
create mode 100644 libs/winpthreads/include/pthread_time.h
create mode 100644 libs/winpthreads/include/pthread_unistd.h
create mode 100644 libs/winpthreads/include/sched.h
create mode 100644 libs/winpthreads/include/semaphore.h
create mode 100644 libs/winpthreads/src/barrier.c
create mode 100644 libs/winpthreads/src/barrier.h
create mode 100644 libs/winpthreads/src/clock.c
create mode 100644 libs/winpthreads/src/cond.c
create mode 100644 libs/winpthreads/src/cond.h
create mode 100644 libs/winpthreads/src/libgcc/dll_dependency.S
create mode 100644 libs/winpthreads/src/libgcc/dll_math.c
create mode 100644 libs/winpthreads/src/misc.c
create mode 100644 libs/winpthreads/src/misc.h
create mode 100644 libs/winpthreads/src/mutex.c
create mode 100644 libs/winpthreads/src/nanosleep.c
create mode 100644 libs/winpthreads/src/ref.c
create mode 100644 libs/winpthreads/src/ref.h
create mode 100644 libs/winpthreads/src/rwlock.c
create mode 100644 libs/winpthreads/src/rwlock.h
create mode 100644 libs/winpthreads/src/sched.c
create mode 100644 libs/winpthreads/src/sem.c
create mode 100644 libs/winpthreads/src/sem.h
create mode 100644 libs/winpthreads/src/spinlock.c
create mode 100644 libs/winpthreads/src/thread.c
create mode 100644 libs/winpthreads/src/thread.h
create mode 100644 libs/winpthreads/src/version.rc
create mode 100644 libs/winpthreads/src/winpthread_internal.h
create mode 100644 libs/winpthreads/src/wpth_ver.h
diff --git a/configure.ac b/configure.ac
index 20f08be0063..ff393285c0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1159,6 +1159,7 @@ WINE_EXTLIB_FLAGS(JXR, jxr, jxr, "-I\$(top_srcdir)/libs/jxr/jxrgluelib -I\$(top_
WINE_EXTLIB_FLAGS(LCMS2, lcms2, lcms2, "-I\$(top_srcdir)/libs/lcms2/include")
WINE_EXTLIB_FLAGS(MPG123, mpg123, mpg123, "-I\$(top_srcdir)/libs/mpg123/src/libmpg123")
WINE_EXTLIB_FLAGS(PNG, png, "png \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/png")
+WINE_EXTLIB_FLAGS(PTHREAD, pthread, pthread, "-I\$(top_srcdir)/libs/winpthreads/include")
WINE_EXTLIB_FLAGS(TIFF, tiff, tiff, "-I\$(top_srcdir)/libs/tiff/libtiff")
WINE_EXTLIB_FLAGS(XML2, xml2, xml2, "-I\$(top_srcdir)/libs/xml2/include -DLIBXML_STATIC")
WINE_EXTLIB_FLAGS(XSLT, xslt, xslt, "-I\$(top_srcdir)/libs/xslt -DLIBXSLT_STATIC")
@@ -3705,6 +3706,7 @@ WINE_CONFIG_MAKEFILE(libs/tiff)
WINE_CONFIG_MAKEFILE(libs/uuid)
WINE_CONFIG_MAKEFILE(libs/wbemuuid)
WINE_CONFIG_MAKEFILE(libs/wine)
+WINE_CONFIG_MAKEFILE(libs/winpthreads)
WINE_CONFIG_MAKEFILE(libs/wmcodecdspuuid)
WINE_CONFIG_MAKEFILE(libs/xml2)
WINE_CONFIG_MAKEFILE(libs/xslt)
diff --git a/libs/winpthreads/Makefile.in b/libs/winpthreads/Makefile.in
new file mode 100644
index 00000000000..4e3b4fba682
--- /dev/null
+++ b/libs/winpthreads/Makefile.in
@@ -0,0 +1,11 @@
+EXTLIB = libpthread.a
+
+C_SRCS = \
+ src/clock.c \
+ src/cond.c \
+ src/misc.c \
+ src/mutex.c \
+ src/rwlock.c \
+ src/sched.c \
+ src/spinlock.c \
+ src/thread.c
diff --git a/libs/winpthreads/include/pthread.h b/libs/winpthreads/include/pthread.h
new file mode 100644
index 00000000000..4c2affd36c3
--- /dev/null
+++ b/libs/winpthreads/include/pthread.h
@@ -0,0 +1,692 @@
+/*
+ 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.
+*/
+
+/*
+ * Parts of this library are derived by:
+ *
+ * Posix Threads library for Microsoft Windows
+ *
+ * Use at own risk, there is no implied warranty to this code.
+ * It uses undocumented features of Microsoft Windows that can change
+ * at any time in the future.
+ *
+ * (C) 2010 Lockless Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef WIN_PTHREADS_H
+#define WIN_PTHREADS_H
+
+#include <stddef.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <process.h>
+#include <limits.h>
+#include <signal.h>
+
+#include <sys/timeb.h>
+
+#include "pthread_compat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define __WINPTHREADS_VERSION_MAJOR 0
+#define __WINPTHREADS_VERSION_MINOR 5
+#define __WINPTHREADS_VERSION_PATCHLEVEL 0
+
+/* MSB 8-bit major version, 8-bit minor version, 16-bit patch level. */
+#define __WINPTHREADS_VERSION 0x00050000
+
+#if defined DLL_EXPORT
+#ifdef IN_WINPTHREAD
+#define WINPTHREAD_API __declspec(dllexport)
+#else
+#define WINPTHREAD_API __declspec(dllimport)
+#endif
+#else
+#define WINPTHREAD_API
+#endif
+
+/* #define WINPTHREAD_DBG 1 */
+
+/* Compatibility stuff: */
+#define RWLS_PER_THREAD 8
+
+/* Error-codes. */
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 138
+#endif
+#ifndef ENOTSUP
+#define ENOTSUP 129
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK 140
+#endif
+
+/* pthread specific defines. */
+
+#define PTHREAD_CANCEL_DISABLE 0
+#define PTHREAD_CANCEL_ENABLE 0x01
+
+#define PTHREAD_CANCEL_DEFERRED 0
+#define PTHREAD_CANCEL_ASYNCHRONOUS 0x02
+
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 0x04
+
+#define PTHREAD_EXPLICIT_SCHED 0
+#define PTHREAD_INHERIT_SCHED 0x08
+
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM 0x10
+
+#define PTHREAD_DEFAULT_ATTR (PTHREAD_CANCEL_ENABLE)
+
+#define PTHREAD_CANCELED ((void *) (intptr_t) 0xDEADBEEF)
+
+#define _PTHREAD_NULL_THREAD ((pthread_t) 0)
+
+#define PTHREAD_ONCE_INIT 0
+
+#define PTHREAD_DESTRUCTOR_ITERATIONS 256
+#define PTHREAD_KEYS_MAX (1<<20)
+
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_RECURSIVE 2
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+
+#define PTHREAD_MUTEX_SHARED 1
+#define PTHREAD_MUTEX_PRIVATE 0
+
+#define PTHREAD_PRIO_NONE 0
+#define PTHREAD_PRIO_INHERIT 8
+#define PTHREAD_PRIO_PROTECT 16
+#define PTHREAD_PRIO_MULT 32
+#define PTHREAD_PROCESS_SHARED 1
+#define PTHREAD_PROCESS_PRIVATE 0
+
+#define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL
+#define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_FAST_NP
+#define PTHREAD_MUTEX_ADAPTIVE_NP PTHREAD_MUTEX_FAST_NP
+#define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK
+#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
+
+void * WINPTHREAD_API pthread_timechange_handler_np(void * dummy);
+int WINPTHREAD_API pthread_delay_np (const struct timespec *interval);
+int WINPTHREAD_API pthread_num_processors_np(void);
+int WINPTHREAD_API pthread_set_num_processors_np(int n);
+
+#define PTHREAD_BARRIER_SERIAL_THREAD 1
+
+/* maximum number of times a read lock may be obtained */
+#define MAX_READ_LOCKS (INT_MAX - 1)
+
+/* No fork() in windows - so ignore this */
+#define pthread_atfork(F1,F2,F3) 0
+
+/* unsupported stuff: */
+#define pthread_mutex_getprioceiling(M, P) ENOTSUP
+#define pthread_mutex_setprioceiling(M, P) ENOTSUP
+#define pthread_getcpuclockid(T, C) ENOTSUP
+#define pthread_attr_getguardsize(A, S) ENOTSUP
+#define pthread_attr_setgaurdsize(A, S) ENOTSUP
+
+typedef long pthread_once_t;
+typedef unsigned pthread_mutexattr_t;
+typedef unsigned pthread_key_t;
+typedef void *pthread_barrierattr_t;
+typedef int pthread_condattr_t;
+typedef int pthread_rwlockattr_t;
+
+/*
+struct _pthread_v;
+
+typedef struct pthread_t {
+ struct _pthread_v *p;
+ int x;
+} pthread_t;
+*/
+
+typedef uintptr_t pthread_t;
+
+typedef struct _pthread_cleanup _pthread_cleanup;
+struct _pthread_cleanup
+{
+ void (*func)(void *);
+ void *arg;
+ _pthread_cleanup *next;
+};
+
+#define pthread_cleanup_push(F, A)\
+{\
+ const _pthread_cleanup _pthread_cup = {(F), (A), *pthread_getclean()};\
+ __sync_synchronize();\
+ *pthread_getclean() = (_pthread_cleanup *) &_pthread_cup;\
+ __sync_synchronize()
+
+/* Note that if async cancelling is used, then there is a race here */
+#define pthread_cleanup_pop(E)\
+ (*pthread_getclean() = _pthread_cup.next, ((E) ? (_pthread_cup.func((pthread_once_t *)_pthread_cup.arg)) : (void)0));}
+
+/* Windows doesn't have this, so declare it ourselves. */
+#ifndef _TIMESPEC_DEFINED
+#define _TIMESPEC_DEFINED
+struct timespec {
+ time_t tv_sec; /* Seconds */
+ long tv_nsec; /* Nanoseconds */
+};
+
+struct itimerspec {
+ struct timespec it_interval; /* Timer period */
+ struct timespec it_value; /* Timer expiration */
+};
+#endif
+
+#ifndef SCHED_OTHER
+/* Some POSIX realtime extensions, mostly stubbed */
+#define SCHED_OTHER 0
+#define SCHED_FIFO 1
+#define SCHED_RR 2
+#define SCHED_MIN SCHED_OTHER
+#define SCHED_MAX SCHED_RR
+
+struct sched_param {
+ int sched_priority;
+};
+
+int WINPTHREAD_API sched_yield(void);
+int WINPTHREAD_API sched_get_priority_min(int pol);
+int WINPTHREAD_API sched_get_priority_max(int pol);
+int WINPTHREAD_API sched_getscheduler(pid_t pid);
+int WINPTHREAD_API sched_setscheduler(pid_t pid, int pol, const struct sched_param *param);
+
+#endif
+
+typedef struct pthread_attr_t pthread_attr_t;
+struct pthread_attr_t
+{
+ unsigned p_state;
+ void *stack;
+ size_t s_size;
+ struct sched_param param;
+};
+
+int WINPTHREAD_API pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
+int WINPTHREAD_API pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
+int WINPTHREAD_API pthread_getschedparam(pthread_t thread, int *pol, struct sched_param *param);
+int WINPTHREAD_API pthread_setschedparam(pthread_t thread, int pol, const struct sched_param *param);
+int WINPTHREAD_API pthread_attr_setschedpolicy (pthread_attr_t *attr, int pol);
+int WINPTHREAD_API pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *pol);
+
+/* synchronization objects */
+typedef intptr_t pthread_spinlock_t;
+typedef intptr_t pthread_mutex_t;
+typedef intptr_t pthread_cond_t;
+typedef intptr_t pthread_rwlock_t;
+typedef void *pthread_barrier_t;
+
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_RECURSIVE 2
+
+#define GENERIC_INITIALIZER -1
+#define GENERIC_ERRORCHECK_INITIALIZER -2
+#define GENERIC_RECURSIVE_INITIALIZER -3
+#define GENERIC_NORMAL_INITIALIZER -1
+#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_INITIALIZER
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_RECURSIVE_INITIALIZER
+#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_ERRORCHECK_INITIALIZER
+#define PTHREAD_NORMAL_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_NORMAL_INITIALIZER
+#define PTHREAD_DEFAULT_MUTEX_INITIALIZER PTHREAD_NORMAL_MUTEX_INITIALIZER
+#define PTHREAD_COND_INITIALIZER (pthread_cond_t)GENERIC_INITIALIZER
+#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)GENERIC_INITIALIZER
+#define PTHREAD_SPINLOCK_INITIALIZER (pthread_spinlock_t)GENERIC_INITIALIZER
+
+extern void WINPTHREAD_API (**_pthread_key_dest)(void *);
+int WINPTHREAD_API pthread_key_create(pthread_key_t *key, void (* dest)(void *));
+int WINPTHREAD_API pthread_key_delete(pthread_key_t key);
+void * WINPTHREAD_API pthread_getspecific(pthread_key_t key);
+int WINPTHREAD_API pthread_setspecific(pthread_key_t key, const void *value);
+
+pthread_t WINPTHREAD_API pthread_self(void);
+int WINPTHREAD_API pthread_once(pthread_once_t *o, void (*func)(void));
+void WINPTHREAD_API pthread_testcancel(void);
+int WINPTHREAD_API pthread_equal(pthread_t t1, pthread_t t2);
+void WINPTHREAD_API pthread_tls_init(void);
+void WINPTHREAD_API _pthread_cleanup_dest(pthread_t t);
+int WINPTHREAD_API pthread_get_concurrency(int *val);
+int WINPTHREAD_API pthread_set_concurrency(int val);
+void WINPTHREAD_API pthread_exit(void *res);
+void WINPTHREAD_API _pthread_invoke_cancel(void);
+int WINPTHREAD_API pthread_cancel(pthread_t t);
+int WINPTHREAD_API pthread_kill(pthread_t t, int sig);
+unsigned WINPTHREAD_API _pthread_get_state(const pthread_attr_t *attr, unsigned flag);
+int WINPTHREAD_API _pthread_set_state(pthread_attr_t *attr, unsigned flag, unsigned val);
+int WINPTHREAD_API pthread_setcancelstate(int state, int *oldstate);
+int WINPTHREAD_API pthread_setcanceltype(int type, int *oldtype);
+int WINPTHREAD_API pthread_create_wrapper(void *args);
+int WINPTHREAD_API pthread_create(pthread_t *th, const pthread_attr_t *attr, void *(* func)(void *), void *arg);
+int WINPTHREAD_API pthread_join(pthread_t t, void **res);
+int WINPTHREAD_API pthread_detach(pthread_t t);
+int WINPTHREAD_API pthread_setname_np(pthread_t thread, const char *name);
+int WINPTHREAD_API pthread_getname_np(pthread_t thread, char *name, size_t len);
+
+
+int WINPTHREAD_API pthread_rwlock_init(pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr);
+int WINPTHREAD_API pthread_rwlock_wrlock(pthread_rwlock_t *l);
+int WINPTHREAD_API pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *ts);
+int WINPTHREAD_API pthread_rwlock_rdlock(pthread_rwlock_t *l);
+int WINPTHREAD_API pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts);
+int WINPTHREAD_API pthread_rwlock_unlock(pthread_rwlock_t *l);
+int WINPTHREAD_API pthread_rwlock_tryrdlock(pthread_rwlock_t *l);
+int WINPTHREAD_API pthread_rwlock_trywrlock(pthread_rwlock_t *l);
+int WINPTHREAD_API pthread_rwlock_destroy (pthread_rwlock_t *l);
+
+int WINPTHREAD_API pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *a);
+int WINPTHREAD_API pthread_cond_destroy(pthread_cond_t *cv);
+int WINPTHREAD_API pthread_cond_signal (pthread_cond_t *cv);
+int WINPTHREAD_API pthread_cond_broadcast (pthread_cond_t *cv);
+int WINPTHREAD_API pthread_cond_wait (pthread_cond_t *cv, pthread_mutex_t *external_mutex);
+int WINPTHREAD_API pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *external_mutex, const struct timespec *t);
+int WINPTHREAD_API pthread_cond_timedwait_relative_np(pthread_cond_t *cv, pthread_mutex_t *external_mutex, const struct timespec *t);
+
+int WINPTHREAD_API pthread_mutex_lock(pthread_mutex_t *m);
+int WINPTHREAD_API pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *ts);
+int WINPTHREAD_API pthread_mutex_unlock(pthread_mutex_t *m);
+int WINPTHREAD_API pthread_mutex_trylock(pthread_mutex_t *m);
+int WINPTHREAD_API pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a);
+int WINPTHREAD_API pthread_mutex_destroy(pthread_mutex_t *m);
+
+int WINPTHREAD_API pthread_barrier_destroy(pthread_barrier_t *b);
+int WINPTHREAD_API pthread_barrier_init(pthread_barrier_t *b, const void *attr, unsigned int count);
+int WINPTHREAD_API pthread_barrier_wait(pthread_barrier_t *b);
+
+int WINPTHREAD_API pthread_spin_init(pthread_spinlock_t *l, int pshared);
+int WINPTHREAD_API pthread_spin_destroy(pthread_spinlock_t *l);
+/* No-fair spinlock due to lack of knowledge of thread number. */
+int WINPTHREAD_API pthread_spin_lock(pthread_spinlock_t *l);
+int WINPTHREAD_API pthread_spin_trylock(pthread_spinlock_t *l);
+int WINPTHREAD_API pthread_spin_unlock(pthread_spinlock_t *l);
+
+int WINPTHREAD_API pthread_attr_init(pthread_attr_t *attr);
+int WINPTHREAD_API pthread_attr_destroy(pthread_attr_t *attr);
+int WINPTHREAD_API pthread_attr_setdetachstate(pthread_attr_t *a, int flag);
+int WINPTHREAD_API pthread_attr_getdetachstate(const pthread_attr_t *a, int *flag);
+int WINPTHREAD_API pthread_attr_setinheritsched(pthread_attr_t *a, int flag);
+int WINPTHREAD_API pthread_attr_getinheritsched(const pthread_attr_t *a, int *flag);
+int WINPTHREAD_API pthread_attr_setscope(pthread_attr_t *a, int flag);
+int WINPTHREAD_API pthread_attr_getscope(const pthread_attr_t *a, int *flag);
+int WINPTHREAD_API pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stack);
+int WINPTHREAD_API pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack);
+int WINPTHREAD_API pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size);
+int WINPTHREAD_API pthread_attr_setstacksize(pthread_attr_t *attr, size_t size);
+
+int WINPTHREAD_API pthread_mutexattr_init(pthread_mutexattr_t *a);
+int WINPTHREAD_API pthread_mutexattr_destroy(pthread_mutexattr_t *a);
+int WINPTHREAD_API pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type);
+int WINPTHREAD_API pthread_mutexattr_settype(pthread_mutexattr_t *a, int type);
+int WINPTHREAD_API pthread_mutexattr_getpshared(const pthread_mutexattr_t *a, int *type);
+int WINPTHREAD_API pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type);
+int WINPTHREAD_API pthread_mutexattr_getprotocol(const pthread_mutexattr_t *a, int *type);
+int WINPTHREAD_API pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type);
+int WINPTHREAD_API pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *a, int * prio);
+int WINPTHREAD_API pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio);
+int WINPTHREAD_API pthread_getconcurrency(void);
+int WINPTHREAD_API pthread_setconcurrency(int new_level);
+
+int WINPTHREAD_API pthread_condattr_destroy(pthread_condattr_t *a);
+int WINPTHREAD_API pthread_condattr_init(pthread_condattr_t *a);
+int WINPTHREAD_API pthread_condattr_getpshared(const pthread_condattr_t *a, int *s);
+int WINPTHREAD_API pthread_condattr_setpshared(pthread_condattr_t *a, int s);
+
+#ifndef __clockid_t_defined
+typedef int clockid_t;
+#define __clockid_t_defined 1
+#endif /* __clockid_t_defined */
+
+int WINPTHREAD_API pthread_condattr_getclock (const pthread_condattr_t *attr,
+ clockid_t *clock_id);
+int WINPTHREAD_API pthread_condattr_setclock(pthread_condattr_t *attr,
+ clockid_t clock_id);
+int WINPTHREAD_API __pthread_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp);
+
+int WINPTHREAD_API pthread_barrierattr_init(void **attr);
+int WINPTHREAD_API pthread_barrierattr_destroy(void **attr);
+int WINPTHREAD_API pthread_barrierattr_setpshared(void **attr, int s);
+int WINPTHREAD_API pthread_barrierattr_getpshared(void **attr, int *s);
+
+/* Private extensions for analysis and internal use. */
+struct _pthread_cleanup ** WINPTHREAD_API pthread_getclean (void);
+void * WINPTHREAD_API pthread_gethandle (pthread_t t);
+void * WINPTHREAD_API pthread_getevent ();
+
+unsigned long long WINPTHREAD_API _pthread_rel_time_in_ms(const struct timespec *ts);
+unsigned long long WINPTHREAD_API _pthread_time_in_ms(void);
+unsigned long long WINPTHREAD_API _pthread_time_in_ms_from_timespec(const struct timespec *ts);
+int WINPTHREAD_API _pthread_tryjoin (pthread_t t, void **res);
+int WINPTHREAD_API pthread_rwlockattr_destroy(pthread_rwlockattr_t *a);
+int WINPTHREAD_API pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s);
+int WINPTHREAD_API pthread_rwlockattr_init(pthread_rwlockattr_t *a);
+int WINPTHREAD_API pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s);
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK 1
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK 2
+#endif
+
+#include <pthread_unistd.h>
+
+#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
+
+#undef _POSIX_THREAD_KEYS_MAX
+#define _POSIX_THREAD_KEYS_MAX PTHREAD_KEYS_MAX
+
+#undef PTHREAD_THREADS_MAX
+#define PTHREAD_THREADS_MAX 2019
+
+#undef _POSIX_SEM_NSEMS_MAX
+#define _POSIX_SEM_NSEMS_MAX 256
+
+#undef SEM_NSEMS_MAX
+#define SEM_NSEMS_MAX 1024
+
+/* Wrap cancellation points. */
+#ifdef __WINPTRHEAD_ENABLE_WRAP_API
+#define accept(...) (pthread_testcancel(), accept(__VA_ARGS__))
+#define aio_suspend(...) (pthread_testcancel(), aio_suspend(__VA_ARGS__))
+#define clock_nanosleep(...) (pthread_testcancel(), clock_nanosleep(__VA_ARGS__))
+#define close(...) (pthread_testcancel(), close(__VA_ARGS__))
+#define connect(...) (pthread_testcancel(), connect(__VA_ARGS__))
+#define creat(...) (pthread_testcancel(), creat(__VA_ARGS__))
+#define fcntl(...) (pthread_testcancel(), fcntl(__VA_ARGS__))
+#define fdatasync(...) (pthread_testcancel(), fdatasync(__VA_ARGS__))
+#define fsync(...) (pthread_testcancel(), fsync(__VA_ARGS__))
+#define getmsg(...) (pthread_testcancel(), getmsg(__VA_ARGS__))
+#define getpmsg(...) (pthread_testcancel(), getpmsg(__VA_ARGS__))
+#define lockf(...) (pthread_testcancel(), lockf(__VA_ARGS__))
+#define mg_receive(...) (pthread_testcancel(), mg_receive(__VA_ARGS__))
+#define mg_send(...) (pthread_testcancel(), mg_send(__VA_ARGS__))
+#define mg_timedreceive(...) (pthread_testcancel(), mg_timedreceive(__VA_ARGS__))
+#define mg_timessend(...) (pthread_testcancel(), mg_timedsend(__VA_ARGS__))
+#define msgrcv(...) (pthread_testcancel(), msgrecv(__VA_ARGS__))
+#define msgsnd(...) (pthread_testcancel(), msgsnd(__VA_ARGS__))
+#define msync(...) (pthread_testcancel(), msync(__VA_ARGS__))
+#define nanosleep(...) (pthread_testcancel(), nanosleep(__VA_ARGS__))
+#define open(...) (pthread_testcancel(), open(__VA_ARGS__))
+#define pause(...) (pthread_testcancel(), pause(__VA_ARGS__))
+#define poll(...) (pthread_testcancel(), poll(__VA_ARGS__))
+#define pread(...) (pthread_testcancel(), pread(__VA_ARGS__))
+#define pselect(...) (pthread_testcancel(), pselect(__VA_ARGS__))
+#define putmsg(...) (pthread_testcancel(), putmsg(__VA_ARGS__))
+#define putpmsg(...) (pthread_testcancel(), putpmsg(__VA_ARGS__))
+#define pwrite(...) (pthread_testcancel(), pwrite(__VA_ARGS__))
+#define read(...) (pthread_testcancel(), read(__VA_ARGS__))
+#define readv(...) (pthread_testcancel(), readv(__VA_ARGS__))
+#define recv(...) (pthread_testcancel(), recv(__VA_ARGS__))
+#define recvfrom(...) (pthread_testcancel(), recvfrom(__VA_ARGS__))
+#define recvmsg(...) (pthread_testcancel(), recvmsg(__VA_ARGS__))
+#define select(...) (pthread_testcancel(), select(__VA_ARGS__))
+#define sem_timedwait(...) (pthread_testcancel(), sem_timedwait(__VA_ARGS__))
+#define sem_wait(...) (pthread_testcancel(), sem_wait(__VA_ARGS__))
+#define send(...) (pthread_testcancel(), send(__VA_ARGS__))
+#define sendmsg(...) (pthread_testcancel(), sendmsg(__VA_ARGS__))
+#define sendto(...) (pthread_testcancel(), sendto(__VA_ARGS__))
+#define sigpause(...) (pthread_testcancel(), sigpause(__VA_ARGS__))
+#define sigsuspend(...) (pthread_testcancel(), sigsuspend(__VA_ARGS__))
+#define sigwait(...) (pthread_testcancel(), sigwait(__VA_ARGS__))
+#define sigwaitinfo(...) (pthread_testcancel(), sigwaitinfo(__VA_ARGS__))
+#define sleep(...) (pthread_testcancel(), sleep(__VA_ARGS__))
+//#define Sleep(...) (pthread_testcancel(), Sleep(__VA_ARGS__))
+#define system(...) (pthread_testcancel(), system(__VA_ARGS__))
+#define access(...) (pthread_testcancel(), access(__VA_ARGS__))
+#define asctime(...) (pthread_testcancel(), asctime(__VA_ARGS__))
+#define catclose(...) (pthread_testcancel(), catclose(__VA_ARGS__))
+#define catgets(...) (pthread_testcancel(), catgets(__VA_ARGS__))
+#define catopen(...) (pthread_testcancel(), catopen(__VA_ARGS__))
+#define closedir(...) (pthread_testcancel(), closedir(__VA_ARGS__))
+#define closelog(...) (pthread_testcancel(), closelog(__VA_ARGS__))
+#define ctermid(...) (pthread_testcancel(), ctermid(__VA_ARGS__))
+#define ctime(...) (pthread_testcancel(), ctime(__VA_ARGS__))
+#define dbm_close(...) (pthread_testcancel(), dbm_close(__VA_ARGS__))
+#define dbm_delete(...) (pthread_testcancel(), dbm_delete(__VA_ARGS__))
+#define dbm_fetch(...) (pthread_testcancel(), dbm_fetch(__VA_ARGS__))
+#define dbm_nextkey(...) (pthread_testcancel(), dbm_nextkey(__VA_ARGS__))
+#define dbm_open(...) (pthread_testcancel(), dbm_open(__VA_ARGS__))
+#define dbm_store(...) (pthread_testcancel(), dbm_store(__VA_ARGS__))
+#define dlclose(...) (pthread_testcancel(), dlclose(__VA_ARGS__))
+#define dlopen(...) (pthread_testcancel(), dlopen(__VA_ARGS__))
+#define endgrent(...) (pthread_testcancel(), endgrent(__VA_ARGS__))
+#define endhostent(...) (pthread_testcancel(), endhostent(__VA_ARGS__))
+#define endnetent(...) (pthread_testcancel(), endnetent(__VA_ARGS__))
+#define endprotoent(...) (pthread_testcancel(), endprotoend(__VA_ARGS__))
+#define endpwent(...) (pthread_testcancel(), endpwent(__VA_ARGS__))
+#define endservent(...) (pthread_testcancel(), endservent(__VA_ARGS__))
+#define endutxent(...) (pthread_testcancel(), endutxent(__VA_ARGS__))
+#define fclose(...) (pthread_testcancel(), fclose(__VA_ARGS__))
+#define fflush(...) (pthread_testcancel(), fflush(__VA_ARGS__))
+#define fgetc(...) (pthread_testcancel(), fgetc(__VA_ARGS__))
+#define fgetpos(...) (pthread_testcancel(), fgetpos(__VA_ARGS__))
+#define fgets(...) (pthread_testcancel(), fgets(__VA_ARGS__))
+#define fgetwc(...) (pthread_testcancel(), fgetwc(__VA_ARGS__))
+#define fgetws(...) (pthread_testcancel(), fgetws(__VA_ARGS__))
+#define fmtmsg(...) (pthread_testcancel(), fmtmsg(__VA_ARGS__))
+#define fopen(...) (pthread_testcancel(), fopen(__VA_ARGS__))
+#define fpathconf(...) (pthread_testcancel(), fpathconf(__VA_ARGS__))
+#define fprintf(...) (pthread_testcancel(), fprintf(__VA_ARGS__))
+#define fputc(...) (pthread_testcancel(), fputc(__VA_ARGS__))
+#define fputs(...) (pthread_testcancel(), fputs(__VA_ARGS__))
+#define fputwc(...) (pthread_testcancel(), fputwc(__VA_ARGS__))
+#define fputws(...) (pthread_testcancel(), fputws(__VA_ARGS__))
+#define fread(...) (pthread_testcancel(), fread(__VA_ARGS__))
+#define freopen(...) (pthread_testcancel(), freopen(__VA_ARGS__))
+#define fscanf(...) (pthread_testcancel(), fscanf(__VA_ARGS__))
+#define fseek(...) (pthread_testcancel(), fseek(__VA_ARGS__))
+#define fseeko(...) (pthread_testcancel(), fseeko(__VA_ARGS__))
+#define fsetpos(...) (pthread_testcancel(), fsetpos(__VA_ARGS__))
+#define fstat(...) (pthread_testcancel(), fstat(__VA_ARGS__))
+#define ftell(...) (pthread_testcancel(), ftell(__VA_ARGS__))
+#define ftello(...) (pthread_testcancel(), ftello(__VA_ARGS__))
+#define ftw(...) (pthread_testcancel(), ftw(__VA_ARGS__))
+#define fwprintf(...) (pthread_testcancel(), fwprintf(__VA_ARGS__))
+#define fwrite(...) (pthread_testcancel(), fwrite(__VA_ARGS__))
+#define fwscanf(...) (pthread_testcancel(), fwscanf(__VA_ARGS__))
+#define getaddrinfo(...) (pthread_testcancel(), getaddrinfo(__VA_ARGS__))
+#define getc(...) (pthread_testcancel(), getc(__VA_ARGS__))
+#define getc_unlocked(...) (pthread_testcancel(), getc_unlocked(__VA_ARGS__))
+#define getchar(...) (pthread_testcancel(), getchar(__VA_ARGS__))
+#define getchar_unlocked(...) (pthread_testcancel(), getchar_unlocked(__VA_ARGS__))
+#define getcwd(...) (pthread_testcancel(), getcwd(__VA_ARGS__))
+#define getdate(...) (pthread_testcancel(), getdate(__VA_ARGS__))
+#define getgrent(...) (pthread_testcancel(), getgrent(__VA_ARGS__))
+#define getgrgid(...) (pthread_testcancel(), getgrgid(__VA_ARGS__))
+#define getgrgid_r(...) (pthread_testcancel(), getgrgid_r(__VA_ARGS__))
+#define gergrnam(...) (pthread_testcancel(), getgrnam(__VA_ARGS__))
+#define getgrnam_r(...) (pthread_testcancel(), getgrnam_r(__VA_ARGS__))
+#define gethostbyaddr(...) (pthread_testcancel(), gethostbyaddr(__VA_ARGS__))
+#define gethostbyname(...) (pthread_testcancel(), gethostbyname(__VA_ARGS__))
+#define gethostent(...) (pthread_testcancel(), gethostent(__VA_ARGS__))
+#define gethostid(...) (pthread_testcancel(), gethostid(__VA_ARGS__))
+#define gethostname(...) (pthread_testcancel(), gethostname(__VA_ARGS__))
+#define getlogin(...) (pthread_testcancel(), getlogin(__VA_ARGS__))
+#define getlogin_r(...) (pthread_testcancel(), getlogin_r(__VA_ARGS__))
+#define getnameinfo(...) (pthread_testcancel(), getnameinfo(__VA_ARGS__))
+#define getnetbyaddr(...) (pthread_testcancel(), getnetbyaddr(__VA_ARGS__))
+#define getnetbyname(...) (pthread_testcancel(), getnetbyname(__VA_ARGS__))
+#define getnetent(...) (pthread_testcancel(), getnetent(__VA_ARGS__))
+#define getopt(...) (pthread_testcancel(), getopt(__VA_ARGS__))
+#define getprotobyname(...) (pthread_testcancel(), getprotobyname(__VA_ARGS__))
+#define getprotobynumber(...) (pthread_testcancel(), getprotobynumber(__VA_ARGS__))
+#define getprotoent(...) (pthread_testcancel(), getprotoent(__VA_ARGS__))
+#define getpwent(...) (pthread_testcancel(), getpwent(__VA_ARGS__))
+#define getpwnam(...) (pthread_testcancel(), getpwnam(__VA_ARGS__))
+#define getpwnam_r(...) (pthread_testcancel(), getpwnam_r(__VA_ARGS__))
+#define getpwuid(...) (pthread_testcancel(), getpwuid(__VA_ARGS__))
+#define getpwuid_r(...) (pthread_testcancel(), getpwuid_r(__VA_ARGS__))
+#define gets(...) (pthread_testcancel(), gets(__VA_ARGS__))
+#define getservbyname(...) (pthread_testcancel(), getservbyname(__VA_ARGS__))
+#define getservbyport(...) (pthread_testcancel(), getservbyport(__VA_ARGS__))
+#define getservent(...) (pthread_testcancel(), getservent(__VA_ARGS__))
+#define getutxent(...) (pthread_testcancel(), getutxent(__VA_ARGS__))
+#define getutxid(...) (pthread_testcancel(), getutxid(__VA_ARGS__))
+#define getutxline(...) (pthread_testcancel(), getutxline(__VA_ARGS__))
+#undef getwc
+#define getwc(...) (pthread_testcancel(), getwc(__VA_ARGS__))
+#undef getwchar
+#define getwchar(...) (pthread_testcancel(), getwchar(__VA_ARGS__))
+#define getwd(...) (pthread_testcancel(), getwd(__VA_ARGS__))
+#define glob(...) (pthread_testcancel(), glob(__VA_ARGS__))
+#define iconv_close(...) (pthread_testcancel(), iconv_close(__VA_ARGS__))
+#define iconv_open(...) (pthread_testcancel(), iconv_open(__VA_ARGS__))
+#define ioctl(...) (pthread_testcancel(), ioctl(__VA_ARGS__))
+#define link(...) (pthread_testcancel(), link(__VA_ARGS__))
+#define localtime(...) (pthread_testcancel(), localtime(__VA_ARGS__))
+#define lseek(...) (pthread_testcancel(), lseek(__VA_ARGS__))
+#define lstat(...) (pthread_testcancel(), lstat(__VA_ARGS__))
+#define mkstemp(...) (pthread_testcancel(), mkstemp(__VA_ARGS__))
+#define nftw(...) (pthread_testcancel(), nftw(__VA_ARGS__))
+#define opendir(...) (pthread_testcancel(), opendir(__VA_ARGS__))
+#define openlog(...) (pthread_testcancel(), openlog(__VA_ARGS__))
+#define pathconf(...) (pthread_testcancel(), pathconf(__VA_ARGS__))
+#define pclose(...) (pthread_testcancel(), pclose(__VA_ARGS__))
+#define perror(...) (pthread_testcancel(), perror(__VA_ARGS__))
+#define popen(...) (pthread_testcancel(), popen(__VA_ARGS__))
+#define posix_fadvise(...) (pthread_testcancel(), posix_fadvise(__VA_ARGS__))
+#define posix_fallocate(...) (pthread_testcancel(), posix_fallocate(__VA_ARGS__))
+#define posix_madvise(...) (pthread_testcancel(), posix_madvise(__VA_ARGS__))
+#define posix_openpt(...) (pthread_testcancel(), posix_openpt(__VA_ARGS__))
+#define posix_spawn(...) (pthread_testcancel(), posix_spawn(__VA_ARGS__))
+#define posix_spawnp(...) (pthread_testcancel(), posix_spawnp(__VA_ARGS__))
+#define posix_trace_clear(...) (pthread_testcancel(), posix_trace_clear(__VA_ARGS__))
+#define posix_trace_close(...) (pthread_testcancel(), posix_trace_close(__VA_ARGS__))
+#define posix_trace_create(...) (pthread_testcancel(), posix_trace_create(__VA_ARGS__))
+#define posix_trace_create_withlog(...) (pthread_testcancel(), posix_trace_create_withlog(__VA_ARGS__))
+#define posix_trace_eventtypelist_getne(...) (pthread_testcancel(), posix_trace_eventtypelist_getne(__VA_ARGS__))
+#define posix_trace_eventtypelist_rewin(...) (pthread_testcancel(), posix_trace_eventtypelist_rewin(__VA_ARGS__))
+#define posix_trace_flush(...) (pthread_testcancel(), posix_trace_flush(__VA_ARGS__))
+#define posix_trace_get_attr(...) (pthread_testcancel(), posix_trace_get_attr(__VA_ARGS__))
+#define posix_trace_get_filter(...) (pthread_testcancel(), posix_trace_get_filter(__VA_ARGS__))
+#define posix_trace_get_status(...) (pthread_testcancel(), posix_trace_get_status(__VA_ARGS__))
+#define posix_trace_getnext_event(...) (pthread_testcancel(), posix_trace_getnext_event(__VA_ARGS__))
+#define posix_trace_open(...) (pthread_testcancel(), posix_trace_open(__VA_ARGS__))
+#define posix_trace_rewind(...) (pthread_testcancel(), posix_trace_rewind(__VA_ARGS__))
+#define posix_trace_setfilter(...) (pthread_testcancel(), posix_trace_setfilter(__VA_ARGS__))
+#define posix_trace_shutdown(...) (pthread_testcancel(), posix_trace_shutdown(__VA_ARGS__))
+#define posix_trace_timedgetnext_event(...) (pthread_testcancel(), posix_trace_timedgetnext_event(__VA_ARGS__))
+#define posix_typed_mem_open(...) (pthread_testcancel(), posix_typed_mem_open(__VA_ARGS__))
+#define printf(...) (pthread_testcancel(), printf(__VA_ARGS__))
+#define putc(...) (pthread_testcancel(), putc(__VA_ARGS__))
+#define putc_unlocked(...) (pthread_testcancel(), putc_unlocked(__VA_ARGS__))
+#define putchar(...) (pthread_testcancel(), putchar(__VA_ARGS__))
+#define putchar_unlocked(...) (pthread_testcancel(), putchar_unlocked(__VA_ARGS__))
+#define puts(...) (pthread_testcancel(), puts(__VA_ARGS__))
+#define pututxline(...) (pthread_testcancel(), pututxline(__VA_ARGS__))
+#undef putwc
+#define putwc(...) (pthread_testcancel(), putwc(__VA_ARGS__))
+#undef putwchar
+#define putwchar(...) (pthread_testcancel(), putwchar(__VA_ARGS__))
+#define readdir(...) (pthread_testcancel(), readdir(__VA_ARSG__))
+#define readdir_r(...) (pthread_testcancel(), readdir_r(__VA_ARGS__))
+#define remove(...) (pthread_testcancel(), remove(__VA_ARGS__))
+#define rename(...) (pthread_testcancel(), rename(__VA_ARGS__))
+#define rewind(...) (pthread_testcancel(), rewind(__VA_ARGS__))
+#define rewinddir(...) (pthread_testcancel(), rewinddir(__VA_ARGS__))
+#define scanf(...) (pthread_testcancel(), scanf(__VA_ARGS__))
+#define seekdir(...) (pthread_testcancel(), seekdir(__VA_ARGS__))
+#define semop(...) (pthread_testcancel(), semop(__VA_ARGS__))
+#define setgrent(...) (pthread_testcancel(), setgrent(__VA_ARGS__))
+#define sethostent(...) (pthread_testcancel(), sethostemt(__VA_ARGS__))
+#define setnetent(...) (pthread_testcancel(), setnetent(__VA_ARGS__))
+#define setprotoent(...) (pthread_testcancel(), setprotoent(__VA_ARGS__))
+#define setpwent(...) (pthread_testcancel(), setpwent(__VA_ARGS__))
+#define setservent(...) (pthread_testcancel(), setservent(__VA_ARGS__))
+#define setutxent(...) (pthread_testcancel(), setutxent(__VA_ARGS__))
+#define stat(...) (pthread_testcancel(), stat(__VA_ARGS__))
+#define strerror(...) (pthread_testcancel(), strerror(__VA_ARGS__))
+#define strerror_r(...) (pthread_testcancel(), strerror_r(__VA_ARGS__))
+#define strftime(...) (pthread_testcancel(), strftime(__VA_ARGS__))
+#define symlink(...) (pthread_testcancel(), symlink(__VA_ARGS__))
+#define sync(...) (pthread_testcancel(), sync(__VA_ARGS__))
+#define syslog(...) (pthread_testcancel(), syslog(__VA_ARGS__))
+#define tmpfile(...) (pthread_testcancel(), tmpfile(__VA_ARGS__))
+#define tmpnam(...) (pthread_testcancel(), tmpnam(__VA_ARGS__))
+#define ttyname(...) (pthread_testcancel(), ttyname(__VA_ARGS__))
+#define ttyname_r(...) (pthread_testcancel(), ttyname_r(__VA_ARGS__))
+#define tzset(...) (pthread_testcancel(), tzset(__VA_ARGS__))
+#define ungetc(...) (pthread_testcancel(), ungetc(__VA_ARGS__))
+#define ungetwc(...) (pthread_testcancel(), ungetwc(__VA_ARGS__))
+#define unlink(...) (pthread_testcancel(), unlink(__VA_ARGS__))
+#define vfprintf(...) (pthread_testcancel(), vfprintf(__VA_ARGS__))
+#define vfwprintf(...) (pthread_testcancel(), vfwprintf(__VA_ARGS__))
+#define vprintf(...) (pthread_testcancel(), vprintf(__VA_ARGS__))
+#define vwprintf(...) (pthread_testcancel(), vwprintf(__VA_ARGS__))
+#define wcsftime(...) (pthread_testcancel(), wcsftime(__VA_ARGS__))
+#define wordexp(...) (pthread_testcancel(), wordexp(__VA_ARGS__))
+#define wprintf(...) (pthread_testcancel(), wprintf(__VA_ARGS__))
+#define wscanf(...) (pthread_testcancel(), wscanf(__VA_ARGS__))
+#endif
+
+/* We deal here with a gcc issue for posix threading on Windows.
+ We would need to change here gcc's gthr-posix.h header, but this
+ got rejected. So we deal it within this header. */
+#ifdef _GTHREAD_USE_MUTEX_INIT_FUNC
+#undef _GTHREAD_USE_MUTEX_INIT_FUNC
+#endif
+#define _GTHREAD_USE_MUTEX_INIT_FUNC 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WIN_PTHREADS_H */
diff --git a/libs/winpthreads/include/pthread_compat.h b/libs/winpthreads/include/pthread_compat.h
new file mode 100644
index 00000000000..63f5f495fcf
--- /dev/null
+++ b/libs/winpthreads/include/pthread_compat.h
@@ -0,0 +1,86 @@
+/*
+ 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.
+*/
+
+/*
+ * Parts of this library are derived by:
+ *
+ * Posix Threads library for Microsoft Windows
+ *
+ * Use at own risk, there is no implied warranty to this code.
+ * It uses undocumented features of Microsoft Windows that can change
+ * at any time in the future.
+ *
+ * (C) 2010 Lockless Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WIN_PTHREADS_PTHREAD_COMPAT_H
+#define WIN_PTHREADS_PTHREAD_COMPAT_H
+
+#ifdef __GNUC__
+
+#define WINPTHREADS_INLINE inline
+#define WINPTHREADS_ATTRIBUTE(X) __attribute__(X)
+#define WINPTHREADS_SECTION(X) __section__(X)
+
+#elif _MSC_VER
+
+#include "pthread_time.h"
+
+#ifdef _WIN64
+typedef __int64 pid_t;
+#else
+typedef int pid_t;
+#endif
+typedef int clockid_t;
+
+#define WINPTHREADS_INLINE __inline
+#define WINPTHREADS_ATTRIBUTE(X) __declspec X
+#define WINPTHREADS_SECTION(X) allocate(X)
+
+#endif
+
+#endif
diff --git a/libs/winpthreads/include/pthread_signal.h b/libs/winpthreads/include/pthread_signal.h
new file mode 100644
index 00000000000..42a50ae06cd
--- /dev/null
+++ b/libs/winpthreads/include/pthread_signal.h
@@ -0,0 +1,29 @@
+/*
+ Copyright (c) 2013-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_SIGNAL_H
+#define WIN_PTHREADS_SIGNAL_H
+
+/* Windows has rudimentary signals support. */
+#define pthread_sigmask(H, S1, S2) 0
+
+#endif /* WIN_PTHREADS_SIGNAL_H */
diff --git a/libs/winpthreads/include/pthread_time.h b/libs/winpthreads/include/pthread_time.h
new file mode 100644
index 00000000000..7a7538c393f
--- /dev/null
+++ b/libs/winpthreads/include/pthread_time.h
@@ -0,0 +1,98 @@
+/*
+ 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 <sys/timeb.h>
+
+#ifndef WIN_PTHREADS_TIME_H
+#define WIN_PTHREADS_TIME_H
+
+/* Posix timers are supported */
+#ifndef _POSIX_TIMERS
+#define _POSIX_TIMERS 200809L
+#endif
+
+/* Monotonic clocks are available. */
+#ifndef _POSIX_MONOTONIC_CLOCK
+#define _POSIX_MONOTONIC_CLOCK 200809L
+#endif
+
+/* CPU-time clocks are available. */
+#ifndef _POSIX_CPUTIME
+#define _POSIX_CPUTIME 200809L
+#endif
+
+/* Clock support in threads are available. */
+#ifndef _POSIX_THREAD_CPUTIME
+#define _POSIX_THREAD_CPUTIME 200809L
+#endif
+
+#ifndef __clockid_t_defined
+typedef int clockid_t;
+#define __clockid_t_defined 1
+#endif /* __clockid_t_defined */
+
+#ifndef TIMER_ABSTIME
+#define TIMER_ABSTIME 1
+#endif
+
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+#endif
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+
+#ifndef CLOCK_PROCESS_CPUTIME_ID
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#endif
+
+#ifndef CLOCK_THREAD_CPUTIME_ID
+#define CLOCK_THREAD_CPUTIME_ID 3
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Make sure we provide default for WINPTHREAD_API, if not defined. */
+#pragma push_macro("WINPTHREAD_API")
+#ifndef WINPTHREAD_API
+#define WINPTHREAD_API
+#endif
+
+/* These should really be dllimport'ed if using winpthread dll */
+int __cdecl WINPTHREAD_API nanosleep(const struct timespec *request, struct timespec *remain);
+
+int __cdecl WINPTHREAD_API clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain);
+int __cdecl WINPTHREAD_API clock_getres(clockid_t clock_id, struct timespec *res);
+int __cdecl WINPTHREAD_API clock_gettime(clockid_t clock_id, struct timespec *tp);
+int __cdecl WINPTHREAD_API clock_settime(clockid_t clock_id, const struct timespec *tp);
+
+#pragma pop_macro("WINPTHREAD_API")
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WIN_PTHREADS_TIME_H */
+
diff --git a/libs/winpthreads/include/pthread_unistd.h b/libs/winpthreads/include/pthread_unistd.h
new file mode 100644
index 00000000000..646935344b1
--- /dev/null
+++ b/libs/winpthreads/include/pthread_unistd.h
@@ -0,0 +1,192 @@
+/*
+ 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_UNISTD_H
+#define WIN_PTHREADS_UNISTD_H
+
+/* Set defines described by the POSIX Threads Extension (1003.1c-1995) */
+/* _SC_THREADS
+ Basic support for POSIX threads is available. The functions
+
+ pthread_atfork(),
+ pthread_attr_destroy(),
+ pthread_attr_getdetachstate(),
+ pthread_attr_getschedparam(),
+ pthread_attr_init(),
+ pthread_attr_setdetachstate(),
+ pthread_attr_setschedparam(),
+ pthread_cancel(),
+ pthread_cleanup_push(),
+ pthread_cleanup_pop(),
+ pthread_cond_broadcast(),
+ pthread_cond_destroy(),
+ pthread_cond_init(),
+ pthread_cond_signal(),
+ pthread_cond_timedwait(),
+ pthread_cond_wait(),
+ pthread_condattr_destroy(),
+ pthread_condattr_init(),
+ pthread_create(),
+ pthread_detach(),
+ pthread_equal(),
+ pthread_exit(),
+ pthread_getspecific(),
+ pthread_join(,
+ pthread_key_create(),
+ pthread_key_delete(),
+ pthread_mutex_destroy(),
+ pthread_mutex_init(),
+ pthread_mutex_lock(),
+ pthread_mutex_trylock(),
+ pthread_mutex_unlock(),
+ pthread_mutexattr_destroy(),
+ pthread_mutexattr_init(),
+ pthread_once(),
+ pthread_rwlock_destroy(),
+ pthread_rwlock_init(),
+ pthread_rwlock_rdlock(),
+ pthread_rwlock_tryrdlock(),
+ pthread_rwlock_trywrlock(),
+ pthread_rwlock_unlock(),
+ pthread_rwlock_wrlock(),
+ pthread_rwlockattr_destroy(),
+ pthread_rwlockattr_init(),
+ pthread_self(),
+ pthread_setcancelstate(),
+ pthread_setcanceltype(),
+ pthread_setspecific(),
+ pthread_testcancel()
+
+ are present. */
+#undef _POSIX_THREADS
+#define _POSIX_THREADS 200112L
+
+/* _SC_READER_WRITER_LOCKS
+ This option implies the _POSIX_THREADS option. Conversely, under
+ POSIX 1003.1-2001 the _POSIX_THREADS option implies this option.
+
+ The functions
+ pthread_rwlock_destroy(),
+ pthread_rwlock_init(),
+ pthread_rwlock_rdlock(),
+ pthread_rwlock_tryrdlock(),
+ pthread_rwlock_trywrlock(),
+ pthread_rwlock_unlock(),
+ pthread_rwlock_wrlock(),
+ pthread_rwlockattr_destroy(),
+ pthread_rwlockattr_init()
+
+ are present.
+*/
+#undef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS 200112L
+
+/* _SC_SPIN_LOCKS
+ This option implies the _POSIX_THREADS and _POSIX_THREAD_SAFE_FUNCTIONS
+ options. The functions
+
+ pthread_spin_destroy(),
+ pthread_spin_init(),
+ pthread_spin_lock(),
+ pthread_spin_trylock(),
+ pthread_spin_unlock()
+
+ are present. */
+#undef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS 200112L
+
+/* _SC_BARRIERS
+ This option implies the _POSIX_THREADS and _POSIX_THREAD_SAFE_FUNCTIONS
+ options. The functions
+
+ pthread_barrier_destroy(),
+ pthread_barrier_init(),
+ pthread_barrier_wait(),
+ pthread_barrierattr_destroy(),
+ pthread_barrierattr_init()
+
+ are present.
+*/
+#undef _POSIX_BARRIERS
+#define _POSIX_BARRIERS 200112L
+
+/* _SC_TIMEOUTS
+ The functions
+
+ mq_timedreceive(), - not supported
+ mq_timedsend(), - not supported
+ posix_trace_timedgetnext_event(), - not supported
+ pthread_mutex_timedlock(),
+ pthread_rwlock_timedrdlock(),
+ pthread_rwlock_timedwrlock(),
+ sem_timedwait(),
+
+ are present. */
+#undef _POSIX_TIMEOUTS
+#define _POSIX_TIMEOUTS 200112L
+
+/* _SC_TIMERS - not supported
+ The functions
+
+ clock_getres(),
+ clock_gettime(),
+ clock_settime(),
+ nanosleep(),
+ timer_create(),
+ timer_delete(),
+ timer_gettime(),
+ timer_getoverrun(),
+ timer_settime()
+
+ are present. */
+/* #undef _POSIX_TIMERS */
+
+/* _SC_CLOCK_SELECTION
+ This option implies the _POSIX_TIMERS option. The functions
+
+ pthread_condattr_getclock(),
+ pthread_condattr_setclock(),
+ clock_nanosleep()
+
+ are present.
+*/
+#undef _POSIX_CLOCK_SELECTION
+#define _POSIX_CLOCK_SELECTION 200112
+
+/* _SC_SEMAPHORES
+ The include file <semaphore.h> is present. The functions
+
+ sem_close(),
+ sem_destroy(),
+ sem_getvalue(),
+ sem_init(),
+ sem_open(),
+ sem_post(),
+ sem_trywait(),
+ sem_unlink(),
+ sem_wait()
+
+ are present. */
+#undef _POSIX_SEMAPHORES
+#define _POSIX_SEMAPHORES 200112
+
+#endif /* WIN_PTHREADS_UNISTD_H */
diff --git a/libs/winpthreads/include/sched.h b/libs/winpthreads/include/sched.h
new file mode 100644
index 00000000000..e77bf4cc3be
--- /dev/null
+++ b/libs/winpthreads/include/sched.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.
+*/
+
+#include <stddef.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <process.h>
+#include <limits.h>
+#include <signal.h>
+
+#include <sys/timeb.h>
+
+#ifndef WIN_PTHREADS_SCHED_H
+#define WIN_PTHREADS_SCHED_H
+
+#ifndef SCHED_OTHER
+/* Some POSIX realtime extensions, mostly stubbed */
+#define SCHED_OTHER 0
+#define SCHED_FIFO 1
+#define SCHED_RR 2
+#define SCHED_MIN SCHED_OTHER
+#define SCHED_MAX SCHED_RR
+
+struct sched_param {
+ int sched_priority;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined DLL_EXPORT && !defined (WINPTHREAD_EXPORT_ALL_DEBUG)
+#ifdef IN_WINPTHREAD
+#define WINPTHREAD_SCHED_API __declspec(dllexport)
+#else
+#define WINPTHREAD_SCHED_API __declspec(dllimport)
+#endif
+#else
+#define WINPTHREAD_SCHED_API
+#endif
+
+int WINPTHREAD_SCHED_API sched_yield(void);
+int WINPTHREAD_SCHED_API sched_get_priority_min(int pol);
+int WINPTHREAD_SCHED_API sched_get_priority_max(int pol);
+int WINPTHREAD_SCHED_API sched_getscheduler(pid_t pid);
+int WINPTHREAD_SCHED_API sched_setscheduler(pid_t pid, int pol, const struct sched_param *param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef sched_rr_get_interval
+#define sched_rr_get_interval(_p, _i) \
+ ( errno = ENOTSUP, (int) -1 )
+#endif
+
+#endif /* WIN_PTHREADS_SCHED_H */
diff --git a/libs/winpthreads/include/semaphore.h b/libs/winpthreads/include/semaphore.h
new file mode 100644
index 00000000000..14cb703713f
--- /dev/null
+++ b/libs/winpthreads/include/semaphore.h
@@ -0,0 +1,81 @@
+/*
+ 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_SEMAPHORE_H
+#define WIN_PTHREADS_SEMAPHORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined DLL_EXPORT && !defined (WINPTHREAD_EXPORT_ALL_DEBUG)
+#ifdef IN_WINPTHREAD
+#define WINPTHREAD_SEMA_API __declspec(dllexport)
+#else
+#define WINPTHREAD_SEMA_API __declspec(dllimport)
+#endif
+#else
+#define WINPTHREAD_SEMA_API
+#endif
+
+/* Set this to 0 to disable it */
+#define USE_SEM_CriticalSection_SpinCount 100
+
+#define SEM_VALUE_MAX INT_MAX
+
+#ifndef _MODE_T_
+#define _MODE_T_
+typedef unsigned short mode_t;
+#endif
+
+typedef void *sem_t;
+
+#define SEM_FAILED NULL
+
+int WINPTHREAD_SEMA_API sem_init(sem_t * sem, int pshared, unsigned int value);
+
+int WINPTHREAD_SEMA_API sem_destroy(sem_t *sem);
+
+int WINPTHREAD_SEMA_API sem_trywait(sem_t *sem);
+
+int WINPTHREAD_SEMA_API sem_wait(sem_t *sem);
+
+int WINPTHREAD_SEMA_API sem_timedwait(sem_t * sem, const struct timespec *t);
+
+int WINPTHREAD_SEMA_API sem_post(sem_t *sem);
+
+int WINPTHREAD_SEMA_API sem_post_multiple(sem_t *sem, int count);
+
+/* yes, it returns a semaphore (or SEM_FAILED) */
+sem_t * WINPTHREAD_SEMA_API sem_open(const char * name, int oflag, mode_t mode, unsigned int value);
+
+int WINPTHREAD_SEMA_API sem_close(sem_t * sem);
+
+int WINPTHREAD_SEMA_API sem_unlink(const char * name);
+
+int WINPTHREAD_SEMA_API sem_getvalue(sem_t * sem, int * sval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WIN_PTHREADS_SEMAPHORE_H */
diff --git a/libs/winpthreads/src/barrier.c b/libs/winpthreads/src/barrier.c
new file mode 100644
index 00000000000..95b2252af59
--- /dev/null
+++ b/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))))
+ 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))) 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))))
+ 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/libs/winpthreads/src/barrier.h b/libs/winpthreads/src/barrier.h
new file mode 100644
index 00000000000..b3e2146e7eb
--- /dev/null
+++ b/libs/winpthreads/src/barrier.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_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) { \
+ if (!(b) || ( ((barrier_t *)(*b))->valid != (unsigned int)LIFE_BARRIER ) ) return EINVAL; }
+
+#include "../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/libs/winpthreads/src/clock.c b/libs/winpthreads/src/clock.c
new file mode 100644
index 00000000000..5ad710b2e22
--- /dev/null
+++ b/libs/winpthreads/src/clock.c
@@ -0,0 +1,240 @@
+/**
+ * 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"
+
+#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)
+{
+ switch(clock_id) {
+ 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:
+ 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:
+ {
+ 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/libs/winpthreads/src/cond.c b/libs/winpthreads/src/cond.c
new file mode 100644
index 00000000000..d50f85b40b2
--- /dev/null
+++ b/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 %d %s\n",(void *)*c,(int)GetCurrentThreadId(),txt);
+ } else {
+ fprintf(fo,"C%p %d V=%0X w=%ld %s\n",
+ (void *)*c,
+ (int)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))) ) {
+ 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/libs/winpthreads/src/cond.h b/libs/winpthreads/src/cond.h
new file mode 100644
index 00000000000..c70d3114617
--- /dev/null
+++ b/libs/winpthreads/src/cond.h
@@ -0,0 +1,61 @@
+/*
+ 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) { \
+ if (!(c) || !*c || (*c == PTHREAD_COND_INITIALIZER) \
+ || ( ((cond_t *)(*c))->valid != (unsigned int)LIFE_COND ) ) \
+ return EINVAL; }
+
+#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/libs/winpthreads/src/libgcc/dll_dependency.S b/libs/winpthreads/src/libgcc/dll_dependency.S
new file mode 100644
index 00000000000..0496e9406fe
--- /dev/null
+++ b/libs/winpthreads/src/libgcc/dll_dependency.S
@@ -0,0 +1,90 @@
+/* Implementation for gcc's internal stack-allocation routines. */
+#if defined(__i386__) || defined(__x86_64__)
+.global ___chkstk
+.global __alloca
+
+.global ___chkstk_ms
+___chkstk_ms:
+#ifdef _WIN64
+ pushq %rax
+ pushq %rcx
+ cmpq $0x1000, %rax
+ leaq 24(%rsp), %rcx
+ jb .Lchkstk_ms_end
+.Lchkstk_ms_loop:
+ subq $0x1000, %rcx
+ subq $0x1000, %rax
+ orq $0x0, (%rcx)
+ cmpq $0x1000, %rax
+ ja .Lchkstk_ms_loop
+.Lchkstk_ms_end:
+ subq %rax, %rcx
+ orq $0x0, (%rcx)
+ popq %rcx
+ popq %rax
+ ret
+#else
+ pushl %eax
+ pushl %ecx
+ cmpl $0x1000, %eax
+ leal 12(%esp), %ecx
+ jb chkstk_ms_end
+chkstk_ms_loop:
+ subl $0x1000, %ecx
+ subl $0x1000, %eax
+ orl $0x0, (%ecx)
+ cmpl $0x1000, %eax
+ ja chkstk_ms_loop
+chkstk_ms_end:
+ subl %eax, %ecx
+ orl $0x0, (%ecx)
+ popl %ecx
+ popl %eax
+ ret
+#endif
+
+#ifdef _WIN64
+__alloca:
+ movq %rcx, %rax
+.align 4
+___chkstk:
+ popq %r11
+ movq %rsp, %r10
+ cmpq $0x1000, %rax
+ jb .Lchkstk_end
+.Lchkstk_loop:
+ subq $0x1000, %r10
+ subq $0x1000, %rax
+ orl $0x0, (%r10)
+ cmpq $0x1000, %rax
+ ja .Lchkstk_loop
+.Lchkstk_end:
+ subq %rax, %r10
+ movq %rsp, %rax
+ orl $0x0, (%r10)
+ movq %r10, %rsp
+ pushq %r11
+ ret
+#else
+___chkstk:
+__alloca:
+ pushl %ecx
+ leal 8(%esp), %ecx
+ cmpl $0x1000, %eax /* > 4k ?*/
+ jb chkstk_end
+chkstk_loop:
+ subl $0x1000, %ecx
+ subl $0x1000, %eax
+ orl $0x0, (%ecx)
+ cmpl $0x1000, %eax
+ ja chkstk_loop
+chkstk_end:
+ subl %eax, %ecx
+ orl $0x0, (%ecx)
+ movl %esp, %eax
+ movl %ecx, %esp
+ movl (%eax), %ecx
+ pushl 4(%eax)
+ ret
+#endif
+#endif
diff --git a/libs/winpthreads/src/libgcc/dll_math.c b/libs/winpthreads/src/libgcc/dll_math.c
new file mode 100644
index 00000000000..aeec068055c
--- /dev/null
+++ b/libs/winpthreads/src/libgcc/dll_math.c
@@ -0,0 +1,579 @@
+/*-
+ * 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);
+
+#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);
+}
+
+#else
+static int __attribute__((unused)) dummy;
+#endif /*deined (_X86_) && !defined (__x86_64__)*/
+
diff --git a/libs/winpthreads/src/misc.c b/libs/winpthreads/src/misc.c
new file mode 100644
index 00000000000..16ed488ecf5
--- /dev/null
+++ b/libs/winpthreads/src/misc.c
@@ -0,0 +1,158 @@
+/*
+ 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 "pthread.h"
+#include "windows.h"
+#include "misc.h"
+
+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 defined (_WIN32_WINNT) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+ (void) frequency; /* unused */
+ return GetTickCount64 ();
+#else
+ LARGE_INTEGER freq, timestamp;
+
+ if (*frequency == 0)
+ {
+ if (QueryPerformanceFrequency (&freq))
+ *frequency = freq.QuadPart;
+ else
+ *frequency = -1;
+ }
+
+ if (*frequency > 0 && QueryPerformanceCounter (×tamp))
+ return timestamp.QuadPart / (*frequency / 1000);
+
+ /* Fallback */
+ return GetTickCount ();
+#endif
+}
+
+/* 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/libs/winpthreads/src/misc.h b/libs/winpthreads/src/misc.h
new file mode 100644
index 00000000000..cdb242689d2
--- /dev/null
+++ b/libs/winpthreads/src/misc.h
@@ -0,0 +1,114 @@
+/*
+ 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) { DWORD dwFlags; \
+ if (!(h) || ((h) == INVALID_HANDLE_VALUE) || !GetHandleInformation((h), &dwFlags)) \
+ return EINVAL; }
+
+#define CHECK_PTR(p) if (!(p)) return EINVAL;
+
+#define UPD_RESULT(x,r) { int _r=(x); r = r ? r : _r; }
+
+#define CHECK_THREAD(t) { \
+ CHECK_PTR(t); \
+ CHECK_HANDLE(t->h); }
+
+#define CHECK_OBJECT(o, e) { DWORD dwFlags; \
+ if (!(o)) return e; \
+ if (!((o)->h) || (((o)->h) == INVALID_HANDLE_VALUE) || !GetHandleInformation(((o)->h), &dwFlags)) \
+ return e; }
+
+#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;
+}
+
+#ifndef _mm_pause
+#define _mm_pause() {__asm__ __volatile__("pause");}
+#endif
+
+#ifndef _ReadWriteBarrier
+#define _ReadWriteBarrier __sync_synchronize
+#endif
+
+#ifndef YieldProcessor
+#define YieldProcessor _mm_pause
+#endif
+
+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);
+
+#endif
diff --git a/libs/winpthreads/src/mutex.c b/libs/winpthreads/src/mutex.c
new file mode 100644
index 00000000000..c6f26139427
--- /dev/null
+++ b/libs/winpthreads/src/mutex.c
@@ -0,0 +1,385 @@
+/*
+ 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 (__sync_bool_compare_and_swap(m, (pthread_mutex_t)mi, (pthread_mutex_t)new_mi)) {
+ return new_mi;
+ } else {
+ /* Someone created the struct before us. */
+ free(new_mi);
+ return (mutex_impl_t *)*m;
+ }
+}
+
+#define likely(cond) __builtin_expect((cond) != 0, 1)
+#define unlikely(cond) __builtin_expect((cond) != 0, 0)
+
+/* 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)
+ __builtin_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 = __sync_lock_test_and_set(&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. */
+ __sync_bool_compare_and_swap(&mi->state, Locked, old_state);
+ 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 (!__sync_bool_compare_and_swap(&mi->event, NULL, ev)) {
+ /* Someone created the event before us. */
+ CloseHandle(ev);
+ }
+ }
+
+ /* At this point, mi->event is non-NULL. */
+
+ while (__sync_lock_test_and_set(&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(__sync_lock_test_and_set(&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 (__sync_bool_compare_and_swap(&mi->state, Unlocked, Locked)) {
+ 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/libs/winpthreads/src/nanosleep.c b/libs/winpthreads/src/nanosleep.c
new file mode 100644
index 00000000000..0cce4492e29
--- /dev/null
+++ b/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/libs/winpthreads/src/ref.c b/libs/winpthreads/src/ref.c
new file mode 100644
index 00000000000..0344d457e9d
--- /dev/null
+++ b/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/libs/winpthreads/src/ref.h b/libs/winpthreads/src/ref.h
new file mode 100644
index 00000000000..5ca67506fa1
--- /dev/null
+++ b/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/libs/winpthreads/src/rwlock.c b/libs/winpthreads/src/rwlock.c
new file mode 100644
index 00000000000..933d438859f
--- /dev/null
+++ b/libs/winpthreads/src/rwlock.c
@@ -0,0 +1,533 @@
+/*
+ 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;
+ INIT_RWLOCK(rwl);
+ 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 %d %s\n",(void *)*rwl,(int)GetCurrentThreadId(),txt);
+ } else {
+ printf("RWL%p %d V=%0X B=%d r=%ld w=%ld L=%p %s\n",
+ (void *)*rwl,
+ (int)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/libs/winpthreads/src/rwlock.h b/libs/winpthreads/src/rwlock.h
new file mode 100644
index 00000000000..f08b0d37bef
--- /dev/null
+++ b/libs/winpthreads/src/rwlock.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_RWLOCK_H
+#define WIN_PTHREADS_RWLOCK_H
+
+#define LIFE_RWLOCK 0xBAB1F0ED
+#define DEAD_RWLOCK 0xDEADB0EF
+
+#define INIT_RWLOCK(rwl) { int r; \
+ if (STATIC_RWL_INITIALIZER(*rwl)) { if ((r = rwlock_static_init(rwl))) { if (r != EBUSY) return r; }}}
+
+#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/libs/winpthreads/src/sched.c b/libs/winpthreads/src/sched.c
new file mode 100644
index 00000000000..976bcc10521
--- /dev/null
+++ b/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/libs/winpthreads/src/sem.c b/libs/winpthreads/src/sem.c
new file mode 100644
index 00000000000..81fa8f8e636
--- /dev/null
+++ b/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))))
+ 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/libs/winpthreads/src/sem.h b/libs/winpthreads/src/sem.h
new file mode 100644
index 00000000000..3b3ace7f73e
--- /dev/null
+++ b/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/libs/winpthreads/src/spinlock.c b/libs/winpthreads/src/spinlock.c
new file mode 100644
index 00000000000..2032d602a28
--- /dev/null
+++ b/libs/winpthreads/src/spinlock.c
@@ -0,0 +1,81 @@
+/*
+ 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 "pthread.h"
+
+#define likely(cond) __builtin_expect((cond) != 0, 1)
+#define unlikely(cond) __builtin_expect((cond) != 0, 0)
+
+/* 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(__sync_lock_test_and_set(lk, 0) == 0))
+ do {
+#if defined(__i386__) || defined(__x86_64__)
+ asm("pause" ::: "memory");
+#elif defined(__arm__) || defined(__aarch64__)
+ asm("wfe" ::: "memory");
+#else
+#error Unsupported architecture
+#endif
+ } while (*lk == 0);
+ return 0;
+}
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ spinlock_word_t *lk = (spinlock_word_t *)lock;
+ return __sync_lock_test_and_set(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/libs/winpthreads/src/thread.c b/libs/winpthreads/src/thread.c
new file mode 100644
index 00000000000..a9f286ba3a5
--- /dev/null
+++ b/libs/winpthreads/src/thread.c
@@ -0,0 +1,1865 @@
+/*
+ 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;
+}
+#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)
+{
+ _pthread_v *t;
+
+ if (1)
+ return;
+ 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);
+}
+
+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 "
+#define THREADERR_LEN ((sizeof (THREADERR) / sizeof (*THREADERR)) - 1)
+#define THREADID_LEN THREADERR_LEN + 66 + 1 + 1
+ int i;
+ char thread_id[THREADID_LEN] = THREADERR;
+ _ultoa ((unsigned long) GetCurrentThreadId (), &thread_id[THREADERR_LEN], 10);
+ for (i = THREADERR_LEN; thread_id[i] != '\0' && i < THREADID_LEN - 1; i++)
+ {
+ }
+ if (i < THREADID_LEN - 1)
+ {
+ thread_id[i] = '\n';
+ thread_id[i + 1] = '\0';
+ }
+#undef THREADERR
+#undef THREADERR_LEN
+#undef THREADID_LEN
+ OutputDebugStringA (thread_id);
+ abort ();
+ }
+
+ *old = new;
+}
+
+/* Hook for TLS-based deregistration/registration of thread. */
+static BOOL 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)
+ {
+ RemoveVectoredExceptionHandler (SetThreadName_VEH_handle);
+ SetThreadName_VEH_handle = NULL;
+ }
+#endif
+ free_pthread_mem ();
+ }
+ else if (dwReason == DLL_PROCESS_ATTACH)
+ {
+#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
+ SetThreadName_VEH_handle = AddVectoredExceptionHandler (1, &SetThreadName_VEH);
+ /* 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 TRUE;
+ }
+ 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);
+ }
+ }
+ return TRUE;
+}
+
+/* TLS-runtime section variable. */
+#ifdef _MSC_VER
+#pragma section(".CRT$XLF", shared)
+#endif
+PIMAGE_TLS_CALLBACK WINPTHREADS_ATTRIBUTE((WINPTHREADS_SECTION(".CRT$XLF"))) __xl_f = (PIMAGE_TLS_CALLBACK) __dyn_tls_pthread;
+#ifdef _MSC_VER
+#pragma data_seg()
+#endif
+
+#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 %d %s\n",NULL,(int)GetCurrentThreadId(),txt);
+ else
+ {
+ printf("T%p %d V=%0X H=%p %s\n",
+ __pth_gpointer_locked (t),
+ (int)GetCurrentThreadId(),
+ (int) (__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", 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 %d\n", o, (int) *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 %d\n", o, (int) *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 ()
+{
+ _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_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
+int
+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"
+ "\t.seh_handler __C_specific_handler, @except\n"
+ "\t.seh_handlerdata\n"
+ "\t.long 1\n"
+ "\t.rva .tl_start, .tl_end, _gnu_exception_handler ,.tl_end\n"
+ "\t.text"
+ );
+ #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");
+ #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;
+ size_t ssize = 0;
+ pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
+
+ 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 = 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, (unsigned int (__stdcall *)(void *))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/libs/winpthreads/src/thread.h b/libs/winpthreads/src/thread.h
new file mode 100644
index 00000000000..729c5bc68ad
--- /dev/null
+++ b/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 *__pth_gpointer_locked (pthread_t id);
+
+#endif
diff --git a/libs/winpthreads/src/version.rc b/libs/winpthreads/src/version.rc
new file mode 100644
index 00000000000..43a61176377
--- /dev/null
+++ b/libs/winpthreads/src/version.rc
@@ -0,0 +1,62 @@
+/*
+ Copyright (c) 2011 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 <winver.h>
+#include "wpth_ver.h"
+
+#define WPTH_VERSIONINFO_NAME "WinPthreadGC\0"
+#ifdef _WIN64
+#define WPTH_VERSIONINFO_COMMENT "GNU C build -- MinGW-w64 64-bit\0"
+#else
+#define WPTH_VERSIONINFO_COMMENT "GNU C build -- MinGW-w64 32-bit\0"
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION WPTH_VERSION
+ PRODUCTVERSION WPTH_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "POSIX WinThreads for Windows\0"
+ VALUE "ProductVersion", WPTH_VERSION_STRING
+ VALUE "FileVersion", WPTH_VERSION_STRING
+ VALUE "InternalName", WPTH_VERSIONINFO_NAME
+ VALUE "OriginalFilename", WPTH_VERSIONINFO_NAME
+ VALUE "CompanyName", "MingW-W64 Project. All rights reserved.\0"
+ VALUE "LegalCopyright", "Copyright (C) MingW-W64 Project Members 2010-2011\0"
+ VALUE "Licence", "ZPL\0"
+ VALUE "Info", "http://mingw-w64.sourceforge.net/\0"
+ VALUE "Comment", WPTH_VERSIONINFO_COMMENT
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
diff --git a/libs/winpthreads/src/winpthread_internal.h b/libs/winpthreads/src/winpthread_internal.h
new file mode 100644
index 00000000000..015e6ce9c9e
--- /dev/null
+++ b/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
+struct _pthread_v * WINPTHREAD_API __pth_gpointer_locked (pthread_t id);
+int pthread_delay_np_ms (DWORD to);
+#endif /*WINPTHREAD_INTERNAL_H*/
diff --git a/libs/winpthreads/src/wpth_ver.h b/libs/winpthreads/src/wpth_ver.h
new file mode 100644
index 00000000000..1089a612105
--- /dev/null
+++ b/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
--
2.34.0
More information about the wine-devel
mailing list