[Mesa-dev] [PATCH 2/7] c11: Import threads.h emulation library.
Ian Romanick
idr at freedesktop.org
Thu Jan 9 11:36:14 PST 2014
Assuming patch 7 gets squashed in (I sent a comment on that patch),
Acked-by: Ian Romanick <ian.d.romanick at intel.com>
On 01/09/2014 11:20 AM, jfonseca at vmware.com wrote:
> From: José Fonseca <jfonseca at vmware.com>
>
> Implementation is based of https://gist.github.com/2223710 with the
> following modifications:
> - inline implementatation
> - retain XP compatability
> - add temporary hack for static mutex initializers (as they are not part
> of the stack but still widely used internally).
> ---
> include/c11/threads.h | 56 +++++
> include/c11/threads_posix.h | 346 ++++++++++++++++++++++++++
> include/c11/threads_win32.h | 588 ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 990 insertions(+)
> create mode 100644 include/c11/threads.h
> create mode 100644 include/c11/threads_posix.h
> create mode 100644 include/c11/threads_win32.h
>
> diff --git a/include/c11/threads.h b/include/c11/threads.h
> new file mode 100644
> index 0000000..678774c
> --- /dev/null
> +++ b/include/c11/threads.h
> @@ -0,0 +1,56 @@
> +/*
> + * C11 <threads.h> emulation library
> + *
> + * (C) Copyright yohhoy 2012.
> + * Distributed under the Boost Software License, Version 1.0.
> + * (See copy at http://www.boost.org/LICENSE_1_0.txt)
> + */
> +#ifndef EMULATED_THREADS_H_INCLUDED_
> +#define EMULATED_THREADS_H_INCLUDED_
> +
> +#include <time.h>
> +
> +#include "c99_compat.h" /* for `inline` */
> +
> +/*---------------------------- types ----------------------------*/
> +typedef void (*tss_dtor_t)(void*);
> +typedef int (*thrd_start_t)(void*);
> +
> +struct xtime {
> + time_t sec;
> + long nsec;
> +};
> +typedef struct xtime xtime;
> +
> +
> +/*-------------------- enumeration constants --------------------*/
> +enum {
> + mtx_plain = 0,
> + mtx_try = 1,
> + mtx_timed = 2,
> + mtx_recursive = 4
> +};
> +
> +enum {
> + thrd_success = 0, // succeeded
> + thrd_timeout, // timeout
> + thrd_error, // failed
> + thrd_busy, // resource busy
> + thrd_nomem // out of memory
> +};
> +
> +enum { TIME_UTC = 1 };
> +
> +/*-------------------------- functions --------------------------*/
> +
> +#if defined(_WIN32) && !defined(__CYGWIN__)
> +#include "threads_win32.h"
> +#elif defined(__unix__) || defined(__unix)
> +#include "threads_posix.h"
> +#else
> +#error Not supported on this platform.
> +#endif
> +
> +
> +
> +#endif /* EMULATED_THREADS_H_INCLUDED_ */
> diff --git a/include/c11/threads_posix.h b/include/c11/threads_posix.h
> new file mode 100644
> index 0000000..463c93f
> --- /dev/null
> +++ b/include/c11/threads_posix.h
> @@ -0,0 +1,346 @@
> +/*
> + * C11 <threads.h> emulation library
> + *
> + * (C) Copyright yohhoy 2012.
> + * Distributed under the Boost Software License, Version 1.0.
> + * (See copy at http://www.boost.org/LICENSE_1_0.txt)
> + */
> +#include <stdlib.h>
> +#include <assert.h>
> +#include <limits.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <sched.h>
> +#include <stdint.h> /* for intptr_t */
> +
> +/*
> +Configuration macro:
> +
> + EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
> + Use pthread_mutex_timedlock() for `mtx_timedlock()'
> + Otherwise use mtx_trylock() + *busy loop* emulation.
> +*/
> +#if !defined(__CYGWIN__)
> +#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
> +#endif
> +
> +
> +#include <pthread.h>
> +
> +/*---------------------------- macros ----------------------------*/
> +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
> +#ifdef INIT_ONCE_STATIC_INIT
> +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
> +#else
> +#define TSS_DTOR_ITERATIONS 1 // assume TSS dtor MAY be called at least once.
> +#endif
> +
> +// FIXME: temporary non-standard hack to ease transition
> +#define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
> +
> +/*---------------------------- types ----------------------------*/
> +typedef pthread_cond_t cnd_t;
> +typedef pthread_t thrd_t;
> +typedef pthread_key_t tss_t;
> +typedef pthread_mutex_t mtx_t;
> +typedef pthread_once_t once_flag;
> +
> +
> +/*
> +Implementation limits:
> + - Conditionally emulation for "mutex with timeout"
> + (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro)
> +*/
> +struct impl_thrd_param {
> + thrd_start_t func;
> + void *arg;
> +};
> +
> +static inline void *
> +impl_thrd_routine(void *p)
> +{
> + struct impl_thrd_param pack = *((struct impl_thrd_param *)p);
> + free(p);
> + return (void*)(intptr_t)pack.func(pack.arg);
> +}
> +
> +
> +/*--------------- 7.25.2 Initialization functions ---------------*/
> +// 7.25.2.1
> +static inline void
> +call_once(once_flag *flag, void (*func)(void))
> +{
> + pthread_once(flag, func);
> +}
> +
> +
> +/*------------- 7.25.3 Condition variable functions -------------*/
> +// 7.25.3.1
> +static inline int
> +cnd_broadcast(cnd_t *cond)
> +{
> + if (!cond) return thrd_error;
> + pthread_cond_broadcast(cond);
> + return thrd_success;
> +}
> +
> +// 7.25.3.2
> +static inline void
> +cnd_destroy(cnd_t *cond)
> +{
> + assert(cond);
> + pthread_cond_destroy(cond);
> +}
> +
> +// 7.25.3.3
> +static inline int
> +cnd_init(cnd_t *cond)
> +{
> + if (!cond) return thrd_error;
> + pthread_cond_init(cond, NULL);
> + return thrd_success;
> +}
> +
> +// 7.25.3.4
> +static inline int
> +cnd_signal(cnd_t *cond)
> +{
> + if (!cond) return thrd_error;
> + pthread_cond_signal(cond);
> + return thrd_success;
> +}
> +
> +// 7.25.3.5
> +static inline int
> +cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
> +{
> + struct timespec abs_time;
> + int rt;
> + if (!cond || !mtx || !xt) return thrd_error;
> + rt = pthread_cond_timedwait(cond, mtx, &abs_time);
> + if (rt == ETIMEDOUT)
> + return thrd_busy;
> + return (rt == 0) ? thrd_success : thrd_error;
> +}
> +
> +// 7.25.3.6
> +static inline int
> +cnd_wait(cnd_t *cond, mtx_t *mtx)
> +{
> + if (!cond || !mtx) return thrd_error;
> + pthread_cond_wait(cond, mtx);
> + return thrd_success;
> +}
> +
> +
> +/*-------------------- 7.25.4 Mutex functions --------------------*/
> +// 7.25.4.1
> +static inline void
> +mtx_destroy(mtx_t *mtx)
> +{
> + assert(mtx);
> + pthread_mutex_destroy(mtx);
> +}
> +
> +// 7.25.4.2
> +static inline int
> +mtx_init(mtx_t *mtx, int type)
> +{
> + pthread_mutexattr_t attr;
> + if (!mtx) return thrd_error;
> + if (type != mtx_plain && type != mtx_timed && type != mtx_try
> + && type != (mtx_plain|mtx_recursive)
> + && type != (mtx_timed|mtx_recursive)
> + && type != (mtx_try|mtx_recursive))
> + return thrd_error;
> + pthread_mutexattr_init(&attr);
> + if ((type & mtx_recursive) != 0) {
> +#if defined(__linux__) || defined(__linux)
> + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
> +#else
> + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
> +#endif
> + }
> + pthread_mutex_init(mtx, &attr);
> + pthread_mutexattr_destroy(&attr);
> + return thrd_success;
> +}
> +
> +// 7.25.4.3
> +static inline int
> +mtx_lock(mtx_t *mtx)
> +{
> + if (!mtx) return thrd_error;
> + pthread_mutex_lock(mtx);
> + return thrd_success;
> +}
> +
> +// 7.25.4.4
> +static inline int
> +mtx_timedlock(mtx_t *mtx, const xtime *xt)
> +{
> + if (!mtx || !xt) return thrd_error;
> + {
> +#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
> + struct timespec ts;
> + int rt;
> + ts.tv_sec = xt->sec;
> + ts.tv_nsec = xt->nsec;
> + rt = pthread_mutex_timedlock(mtx, &ts);
> + if (rt == 0)
> + return thrd_success;
> + return (rt == ETIMEDOUT) ? thrd_busy : thrd_error;
> +#else
> + time_t expire = time(NULL);
> + expire += xt->sec;
> + while (mtx_trylock(mtx) != thrd_success) {
> + time_t now = time(NULL);
> + if (expire < now)
> + return thrd_busy;
> + // busy loop!
> + thrd_yield();
> + }
> + return thrd_success;
> +#endif
> + }
> +}
> +
> +// 7.25.4.5
> +static inline int
> +mtx_trylock(mtx_t *mtx)
> +{
> + if (!mtx) return thrd_error;
> + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
> +}
> +
> +// 7.25.4.6
> +static inline int
> +mtx_unlock(mtx_t *mtx)
> +{
> + if (!mtx) return thrd_error;
> + pthread_mutex_unlock(mtx);
> + return thrd_success;
> +}
> +
> +
> +/*------------------- 7.25.5 Thread functions -------------------*/
> +// 7.25.5.1
> +static inline int
> +thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
> +{
> + struct impl_thrd_param *pack;
> + if (!thr) return thrd_error;
> + pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param));
> + if (!pack) return thrd_nomem;
> + pack->func = func;
> + pack->arg = arg;
> + if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) {
> + free(pack);
> + return thrd_error;
> + }
> + return thrd_success;
> +}
> +
> +// 7.25.5.2
> +static inline thrd_t
> +thrd_current(void)
> +{
> + return pthread_self();
> +}
> +
> +// 7.25.5.3
> +static inline int
> +thrd_detach(thrd_t thr)
> +{
> + return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
> +}
> +
> +// 7.25.5.4
> +static inline int
> +thrd_equal(thrd_t thr0, thrd_t thr1)
> +{
> + return pthread_equal(thr0, thr1);
> +}
> +
> +// 7.25.5.5
> +static inline void
> +thrd_exit(int res)
> +{
> + pthread_exit((void*)(intptr_t)res);
> +}
> +
> +// 7.25.5.6
> +static inline int
> +thrd_join(thrd_t thr, int *res)
> +{
> + void *code;
> + if (pthread_join(thr, &code) != 0)
> + return thrd_error;
> + if (res)
> + *res = (int)(intptr_t)code;
> + return thrd_success;
> +}
> +
> +// 7.25.5.7
> +static inline void
> +thrd_sleep(const xtime *xt)
> +{
> + struct timespec req;
> + assert(xt);
> + req.tv_sec = xt->sec;
> + req.tv_nsec = xt->nsec;
> + nanosleep(&req, NULL);
> +}
> +
> +// 7.25.5.8
> +static inline void
> +thrd_yield(void)
> +{
> + sched_yield();
> +}
> +
> +
> +/*----------- 7.25.6 Thread-specific storage functions -----------*/
> +// 7.25.6.1
> +static inline int
> +tss_create(tss_t *key, tss_dtor_t dtor)
> +{
> + if (!key) return thrd_error;
> + return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error;
> +}
> +
> +// 7.25.6.2
> +static inline void
> +tss_delete(tss_t key)
> +{
> + pthread_key_delete(key);
> +}
> +
> +// 7.25.6.3
> +static inline void *
> +tss_get(tss_t key)
> +{
> + return pthread_getspecific(key);
> +}
> +
> +// 7.25.6.4
> +static inline int
> +tss_set(tss_t key, void *val)
> +{
> + return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;
> +}
> +
> +
> +/*-------------------- 7.25.7 Time functions --------------------*/
> +// 7.25.6.1
> +static inline int
> +xtime_get(xtime *xt, int base)
> +{
> + if (!xt) return 0;
> + if (base == TIME_UTC) {
> + xt->sec = time(NULL);
> + xt->nsec = 0;
> + return base;
> + }
> + return 0;
> +}
> diff --git a/include/c11/threads_win32.h b/include/c11/threads_win32.h
> new file mode 100644
> index 0000000..5a63e90
> --- /dev/null
> +++ b/include/c11/threads_win32.h
> @@ -0,0 +1,588 @@
> +/*
> + * C11 <threads.h> emulation library
> + *
> + * (C) Copyright yohhoy 2012.
> + * Distributed under the Boost Software License, Version 1.0.
> + * (See copy at http://www.boost.org/LICENSE_1_0.txt)
> + */
> +#include <assert.h>
> +#include <limits.h>
> +#include <errno.h>
> +#include <process.h> // MSVCRT
> +
> +/*
> +Configuration macro:
> +
> + EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> + Use native WindowsAPI one-time initialization function.
> + (requires WinVista or later)
> + Otherwise emulate by mtx_trylock() + *busy loop* for WinXP.
> +
> + EMULATED_THREADS_USE_NATIVE_CV
> + Use native WindowsAPI condition variable object.
> + (requires WinVista or later)
> + Otherwise use emulated implementation for WinXP.
> +
> + EMULATED_THREADS_TSS_DTOR_SLOTNUM
> + Max registerable TSS dtor number.
> +*/
> +
> +// XXX: Retain XP compatability
> +#if 0
> +#if _WIN32_WINNT >= 0x0600
> +// Prefer native WindowsAPI on newer environment.
> +#if !defined(__MINGW32__)
> +#define EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> +#endif
> +#define EMULATED_THREADS_USE_NATIVE_CV
> +#endif
> +#endif
> +#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE
> +
> +
> +#include <windows.h>
> +
> +// check configuration
> +#if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && (_WIN32_WINNT < 0x0600)
> +#error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600
> +#endif
> +
> +#if defined(EMULATED_THREADS_USE_NATIVE_CV) && (_WIN32_WINNT < 0x0600)
> +#error EMULATED_THREADS_USE_NATIVE_CV requires _WIN32_WINNT>=0x0600
> +#endif
> +
> +
> +/*---------------------------- macros ----------------------------*/
> +#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> +#define ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT
> +#else
> +#define ONCE_FLAG_INIT {0}
> +#endif
> +#define TSS_DTOR_ITERATIONS 1
> +
> +// FIXME: temporary non-standard hack to ease transition
> +#define _MTX_INITIALIZER_NP {(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0}
> +
> +/*---------------------------- types ----------------------------*/
> +typedef struct cnd_t {
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + CONDITION_VARIABLE condvar;
> +#else
> + int blocked;
> + int gone;
> + int to_unblock;
> + HANDLE sem_queue;
> + HANDLE sem_gate;
> + CRITICAL_SECTION monitor;
> +#endif
> +} cnd_t;
> +
> +typedef HANDLE thrd_t;
> +
> +typedef DWORD tss_t;
> +
> +typedef CRITICAL_SECTION mtx_t;
> +
> +#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> +typedef INIT_ONCE once_flag;
> +#else
> +typedef struct once_flag_t {
> + volatile LONG status;
> +} once_flag;
> +#endif
> +
> +
> +static inline void * tss_get(tss_t key);
> +static inline void thrd_yield(void);
> +static inline int mtx_trylock(mtx_t *mtx);
> +static inline int mtx_lock(mtx_t *mtx);
> +static inline int mtx_unlock(mtx_t *mtx);
> +
> +/*
> +Implementation limits:
> + - Conditionally emulation for "Initialization functions"
> + (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro)
> + - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop*
> +*/
> +static void impl_tss_dtor_invoke(void); // forward decl.
> +
> +struct impl_thrd_param {
> + thrd_start_t func;
> + void *arg;
> +};
> +
> +static unsigned __stdcall impl_thrd_routine(void *p)
> +{
> + struct impl_thrd_param pack;
> + int code;
> + memcpy(&pack, p, sizeof(struct impl_thrd_param));
> + free(p);
> + code = pack.func(pack.arg);
> + impl_tss_dtor_invoke();
> + return (unsigned)code;
> +}
> +
> +static DWORD impl_xtime2msec(const xtime *xt)
> +{
> + return (DWORD)((xt->sec * 1000u) + (xt->nsec / 1000));
> +}
> +
> +#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> +struct impl_call_once_param { void (*func)(void); };
> +static BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
> +{
> + struct impl_call_once_param *param = (struct impl_call_once_param*)Parameter;
> + (param->func)();
> + ((void)InitOnce); ((void)Context); // suppress warning
> + return TRUE;
> +}
> +#endif // ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> +
> +#ifndef EMULATED_THREADS_USE_NATIVE_CV
> +/*
> +Note:
> + The implementation of condition variable is ported from Boost.Interprocess
> + See http://www.boost.org/boost/interprocess/sync/windows/condition.hpp
> +*/
> +static void impl_cond_do_signal(cnd_t *cond, int broadcast)
> +{
> + int nsignal = 0;
> +
> + EnterCriticalSection(&cond->monitor);
> + if (cond->to_unblock != 0) {
> + if (cond->blocked == 0) {
> + LeaveCriticalSection(&cond->monitor);
> + return;
> + }
> + if (broadcast) {
> + cond->to_unblock += nsignal = cond->blocked;
> + cond->blocked = 0;
> + } else {
> + nsignal = 1;
> + cond->to_unblock++;
> + cond->blocked--;
> + }
> + } else if (cond->blocked > cond->gone) {
> + WaitForSingleObject(cond->sem_gate, INFINITE);
> + if (cond->gone != 0) {
> + cond->blocked -= cond->gone;
> + cond->gone = 0;
> + }
> + if (broadcast) {
> + nsignal = cond->to_unblock = cond->blocked;
> + cond->blocked = 0;
> + } else {
> + nsignal = cond->to_unblock = 1;
> + cond->blocked--;
> + }
> + }
> + LeaveCriticalSection(&cond->monitor);
> +
> + if (0 < nsignal)
> + ReleaseSemaphore(cond->sem_queue, nsignal, NULL);
> +}
> +
> +static int impl_cond_do_wait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
> +{
> + int nleft = 0;
> + int ngone = 0;
> + int timeout = 0;
> + DWORD w;
> +
> + WaitForSingleObject(cond->sem_gate, INFINITE);
> + cond->blocked++;
> + ReleaseSemaphore(cond->sem_gate, 1, NULL);
> +
> + mtx_unlock(mtx);
> +
> + w = WaitForSingleObject(cond->sem_queue, xt ? impl_xtime2msec(xt) : INFINITE);
> + timeout = (w == WAIT_TIMEOUT);
> +
> + EnterCriticalSection(&cond->monitor);
> + if ((nleft = cond->to_unblock) != 0) {
> + if (timeout) {
> + if (cond->blocked != 0) {
> + cond->blocked--;
> + } else {
> + cond->gone++;
> + }
> + }
> + if (--cond->to_unblock == 0) {
> + if (cond->blocked != 0) {
> + ReleaseSemaphore(cond->sem_gate, 1, NULL);
> + nleft = 0;
> + }
> + else if ((ngone = cond->gone) != 0) {
> + cond->gone = 0;
> + }
> + }
> + } else if (++cond->gone == INT_MAX/2) {
> + WaitForSingleObject(cond->sem_gate, INFINITE);
> + cond->blocked -= cond->gone;
> + ReleaseSemaphore(cond->sem_gate, 1, NULL);
> + cond->gone = 0;
> + }
> + LeaveCriticalSection(&cond->monitor);
> +
> + if (nleft == 1) {
> + while (ngone--)
> + WaitForSingleObject(cond->sem_queue, INFINITE);
> + ReleaseSemaphore(cond->sem_gate, 1, NULL);
> + }
> +
> + mtx_lock(mtx);
> + return timeout ? thrd_busy : thrd_success;
> +}
> +#endif // ifndef EMULATED_THREADS_USE_NATIVE_CV
> +
> +static struct impl_tss_dtor_entry {
> + tss_t key;
> + tss_dtor_t dtor;
> +} impl_tss_dtor_tbl[EMULATED_THREADS_TSS_DTOR_SLOTNUM];
> +
> +static int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor)
> +{
> + int i;
> + for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
> + if (!impl_tss_dtor_tbl[i].dtor)
> + break;
> + }
> + if (i == EMULATED_THREADS_TSS_DTOR_SLOTNUM)
> + return 1;
> + impl_tss_dtor_tbl[i].key = key;
> + impl_tss_dtor_tbl[i].dtor = dtor;
> + return 0;
> +}
> +
> +static void impl_tss_dtor_invoke()
> +{
> + int i;
> + for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
> + if (impl_tss_dtor_tbl[i].dtor) {
> + void* val = tss_get(impl_tss_dtor_tbl[i].key);
> + if (val)
> + (impl_tss_dtor_tbl[i].dtor)(val);
> + }
> + }
> +}
> +
> +
> +/*--------------- 7.25.2 Initialization functions ---------------*/
> +// 7.25.2.1
> +static inline void
> +call_once(once_flag *flag, void (*func)(void))
> +{
> + assert(!flag && !func);
> +#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
> + {
> + struct impl_call_once_param param;
> + param.func = func;
> + InitOnceExecuteOnce(flag, impl_call_once_callback, (PVOID)¶m, NULL);
> + }
> +#else
> + if (InterlockedCompareExchange(&flag->status, 1, 0) == 0) {
> + (func)();
> + InterlockedExchange(&flag->status, 2);
> + } else {
> + while (flag->status == 1) {
> + // busy loop!
> + thrd_yield();
> + }
> + }
> +#endif
> +}
> +
> +
> +/*------------- 7.25.3 Condition variable functions -------------*/
> +// 7.25.3.1
> +static inline int
> +cnd_broadcast(cnd_t *cond)
> +{
> + if (!cond) return thrd_error;
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + WakeAllConditionVariable(&cond->condvar);
> +#else
> + impl_cond_do_signal(cond, 1);
> +#endif
> + return thrd_success;
> +}
> +
> +// 7.25.3.2
> +static inline void
> +cnd_destroy(cnd_t *cond)
> +{
> + assert(cond);
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + // do nothing
> +#else
> + CloseHandle(cond->sem_queue);
> + CloseHandle(cond->sem_gate);
> + DeleteCriticalSection(&cond->monitor);
> +#endif
> +}
> +
> +// 7.25.3.3
> +static inline int
> +cnd_init(cnd_t *cond)
> +{
> + if (!cond) return thrd_error;
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + InitializeConditionVariable(&cond->condvar);
> +#else
> + cond->blocked = 0;
> + cond->gone = 0;
> + cond->to_unblock = 0;
> + cond->sem_queue = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
> + cond->sem_gate = CreateSemaphore(NULL, 1, 1, NULL);
> + InitializeCriticalSection(&cond->monitor);
> +#endif
> + return thrd_success;
> +}
> +
> +// 7.25.3.4
> +static inline int
> +cnd_signal(cnd_t *cond)
> +{
> + if (!cond) return thrd_error;
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + WakeConditionVariable(&cond->condvar);
> +#else
> + impl_cond_do_signal(cond, 0);
> +#endif
> + return thrd_success;
> +}
> +
> +// 7.25.3.5
> +static inline int
> +cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
> +{
> + if (!cond || !mtx || !xt) return thrd_error;
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + if (SleepConditionVariableCS(&cond->condvar, mtx, impl_xtime2msec(xt)))
> + return thrd_success;
> + return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error;
> +#else
> + return impl_cond_do_wait(cond, mtx, xt);
> +#endif
> +}
> +
> +// 7.25.3.6
> +static inline int
> +cnd_wait(cnd_t *cond, mtx_t *mtx)
> +{
> + if (!cond || !mtx) return thrd_error;
> +#ifdef EMULATED_THREADS_USE_NATIVE_CV
> + SleepConditionVariableCS(&cond->condvar, mtx, INFINITE);
> +#else
> + impl_cond_do_wait(cond, mtx, NULL);
> +#endif
> + return thrd_success;
> +}
> +
> +
> +/*-------------------- 7.25.4 Mutex functions --------------------*/
> +// 7.25.4.1
> +static inline void
> +mtx_destroy(mtx_t *mtx)
> +{
> + assert(mtx);
> + DeleteCriticalSection(mtx);
> +}
> +
> +// 7.25.4.2
> +static inline int
> +mtx_init(mtx_t *mtx, int type)
> +{
> + if (!mtx) return thrd_error;
> + if (type != mtx_plain && type != mtx_timed && type != mtx_try
> + && type != (mtx_plain|mtx_recursive)
> + && type != (mtx_timed|mtx_recursive)
> + && type != (mtx_try|mtx_recursive))
> + return thrd_error;
> + InitializeCriticalSection(mtx);
> + return thrd_success;
> +}
> +
> +// 7.25.4.3
> +static inline int
> +mtx_lock(mtx_t *mtx)
> +{
> + if (!mtx) return thrd_error;
> + EnterCriticalSection(mtx);
> + return thrd_success;
> +}
> +
> +// 7.25.4.4
> +static inline int
> +mtx_timedlock(mtx_t *mtx, const xtime *xt)
> +{
> + time_t expire, now;
> + if (!mtx || !xt) return thrd_error;
> + expire = time(NULL);
> + expire += xt->sec;
> + while (mtx_trylock(mtx) != thrd_success) {
> + now = time(NULL);
> + if (expire < now)
> + return thrd_busy;
> + // busy loop!
> + thrd_yield();
> + }
> + return thrd_success;
> +}
> +
> +// 7.25.4.5
> +static inline int
> +mtx_trylock(mtx_t *mtx)
> +{
> + if (!mtx) return thrd_error;
> + return TryEnterCriticalSection(mtx) ? thrd_success : thrd_busy;
> +}
> +
> +// 7.25.4.6
> +static inline int
> +mtx_unlock(mtx_t *mtx)
> +{
> + if (!mtx) return thrd_error;
> + LeaveCriticalSection(mtx);
> + return thrd_success;
> +}
> +
> +
> +/*------------------- 7.25.5 Thread functions -------------------*/
> +// 7.25.5.1
> +static inline int
> +thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
> +{
> + struct impl_thrd_param *pack;
> + uintptr_t handle;
> + if (!thr) return thrd_error;
> + pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param));
> + if (!pack) return thrd_nomem;
> + pack->func = func;
> + pack->arg = arg;
> + handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, 0, NULL);
> + if (handle == 0) {
> + if (errno == EAGAIN || errno == EACCES)
> + return thrd_nomem;
> + return thrd_error;
> + }
> + *thr = (thrd_t)handle;
> + return thrd_success;
> +}
> +
> +// 7.25.5.2
> +static inline thrd_t
> +thrd_current(void)
> +{
> + return GetCurrentThread();
> +}
> +
> +// 7.25.5.3
> +static inline int
> +thrd_detach(thrd_t thr)
> +{
> + CloseHandle(thr);
> + return thrd_success;
> +}
> +
> +// 7.25.5.4
> +static inline int
> +thrd_equal(thrd_t thr0, thrd_t thr1)
> +{
> + return (thr0 == thr1);
> +}
> +
> +// 7.25.5.5
> +static inline void
> +thrd_exit(int res)
> +{
> + impl_tss_dtor_invoke();
> + _endthreadex((unsigned)res);
> +}
> +
> +// 7.25.5.6
> +static inline int
> +thrd_join(thrd_t thr, int *res)
> +{
> + DWORD w, code;
> + w = WaitForSingleObject(thr, INFINITE);
> + if (w != WAIT_OBJECT_0)
> + return thrd_error;
> + if (res) {
> + if (!GetExitCodeThread(thr, &code)) {
> + CloseHandle(thr);
> + return thrd_error;
> + }
> + *res = (int)code;
> + }
> + CloseHandle(thr);
> + return thrd_success;
> +}
> +
> +// 7.25.5.7
> +static inline void
> +thrd_sleep(const xtime *xt)
> +{
> + assert(xt);
> + Sleep(impl_xtime2msec(xt));
> +}
> +
> +// 7.25.5.8
> +static inline void
> +thrd_yield(void)
> +{
> + SwitchToThread();
> +}
> +
> +
> +/*----------- 7.25.6 Thread-specific storage functions -----------*/
> +// 7.25.6.1
> +static inline int
> +tss_create(tss_t *key, tss_dtor_t dtor)
> +{
> + if (!key) return thrd_error;
> + *key = TlsAlloc();
> + if (dtor) {
> + if (impl_tss_dtor_register(*key, dtor)) {
> + TlsFree(*key);
> + return thrd_error;
> + }
> + }
> + return (*key != 0xFFFFFFFF) ? thrd_success : thrd_error;
> +}
> +
> +// 7.25.6.2
> +static inline void
> +tss_delete(tss_t key)
> +{
> + TlsFree(key);
> +}
> +
> +// 7.25.6.3
> +static inline void *
> +tss_get(tss_t key)
> +{
> + return TlsGetValue(key);
> +}
> +
> +// 7.25.6.4
> +static inline int
> +tss_set(tss_t key, void *val)
> +{
> + return TlsSetValue(key, val) ? thrd_success : thrd_error;
> +}
> +
> +
> +/*-------------------- 7.25.7 Time functions --------------------*/
> +// 7.25.6.1
> +static inline int
> +xtime_get(xtime *xt, int base)
> +{
> + if (!xt) return 0;
> + if (base == TIME_UTC) {
> + xt->sec = time(NULL);
> + xt->nsec = 0;
> + return base;
> + }
> + return 0;
> +}
>
More information about the mesa-dev
mailing list