c11: Move the implementation of threads.h into c source code
By doing this, now the global variable impl_tss_dtor_tbl are only defined one time. So the memory usage would reduced Signed-off-by: Yonggang Luo <luoyonggang@gmail.com> Reviewed-by: Jesse Natalie <jenatali@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15087>
This commit is contained in:
parent
b7773fd105
commit
e6392fcf3d
|
@ -80,7 +80,7 @@ Mesa Component Licenses
|
|||
+-----------------+------------------------+-----------------------------+
|
||||
| GLX client code | src/glx/ | SGI Free Software License B |
|
||||
+-----------------+------------------------+-----------------------------+
|
||||
| C11 thread | include/c11/threads*.h | Boost (permissive) |
|
||||
| C11 thread | src/c11/impl/threads* | Boost (permissive) |
|
||||
| emulation | | |
|
||||
+-----------------+------------------------+-----------------------------+
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* C11 <threads.h> emulation library
|
||||
*
|
||||
* (C) Copyright yohhoy 2012.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare [[derivative work]]s of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef EMULATED_THREADS_H_INCLUDED_
|
||||
#define EMULATED_THREADS_H_INCLUDED_
|
||||
|
||||
#include "c11/time.h"
|
||||
|
||||
/*---------------------------- types ----------------------------*/
|
||||
typedef void (*tss_dtor_t)(void*);
|
||||
typedef int (*thrd_start_t)(void*);
|
||||
|
||||
|
||||
/*-------------------- enumeration constants --------------------*/
|
||||
enum {
|
||||
mtx_plain = 0,
|
||||
mtx_try = 1,
|
||||
mtx_timed = 2,
|
||||
mtx_recursive = 4
|
||||
};
|
||||
|
||||
enum {
|
||||
thrd_success = 0, // succeeded
|
||||
thrd_timedout, // timed out
|
||||
thrd_error, // failed
|
||||
thrd_busy, // resource busy
|
||||
thrd_nomem // out of memory
|
||||
};
|
||||
|
||||
/*-------------------------- functions --------------------------*/
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include "threads_win32.h"
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
#include "threads_posix.h"
|
||||
#else
|
||||
#error Not supported on this platform.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* EMULATED_THREADS_H_INCLUDED_ */
|
|
@ -1,3 +1,3 @@
|
|||
[*.h]
|
||||
[*.{c,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
|
@ -22,6 +22,12 @@ files_mesa_util_c11 = files(
|
|||
'time.c',
|
||||
)
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
files_mesa_util_c11 += 'threads_win32.c'
|
||||
else
|
||||
files_mesa_util_c11 += 'threads_posix.c'
|
||||
endif
|
||||
|
||||
_libmesa_util_c11 = static_library(
|
||||
'mesa_util_c11',
|
||||
[files_mesa_util_c11],
|
||||
|
|
|
@ -27,15 +27,15 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#ifndef assert
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <stdint.h> /* for intptr_t */
|
||||
|
||||
#include "c11/threads.h"
|
||||
|
||||
/*
|
||||
Configuration macro:
|
||||
|
||||
|
@ -47,27 +47,7 @@ Configuration macro:
|
|||
#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:
|
||||
|
@ -79,7 +59,7 @@ struct impl_thrd_param {
|
|||
void *arg;
|
||||
};
|
||||
|
||||
static inline void *
|
||||
static void *
|
||||
impl_thrd_routine(void *p)
|
||||
{
|
||||
struct impl_thrd_param pack = *((struct impl_thrd_param *)p);
|
||||
|
@ -90,7 +70,7 @@ impl_thrd_routine(void *p)
|
|||
|
||||
/*--------------- 7.25.2 Initialization functions ---------------*/
|
||||
// 7.25.2.1
|
||||
static inline void
|
||||
void
|
||||
call_once(once_flag *flag, void (*func)(void))
|
||||
{
|
||||
pthread_once(flag, func);
|
||||
|
@ -99,7 +79,7 @@ call_once(once_flag *flag, void (*func)(void))
|
|||
|
||||
/*------------- 7.25.3 Condition variable functions -------------*/
|
||||
// 7.25.3.1
|
||||
static inline int
|
||||
int
|
||||
cnd_broadcast(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
|
@ -107,7 +87,7 @@ cnd_broadcast(cnd_t *cond)
|
|||
}
|
||||
|
||||
// 7.25.3.2
|
||||
static inline void
|
||||
void
|
||||
cnd_destroy(cnd_t *cond)
|
||||
{
|
||||
assert(cond);
|
||||
|
@ -115,7 +95,7 @@ cnd_destroy(cnd_t *cond)
|
|||
}
|
||||
|
||||
// 7.25.3.3
|
||||
static inline int
|
||||
int
|
||||
cnd_init(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
|
@ -123,7 +103,7 @@ cnd_init(cnd_t *cond)
|
|||
}
|
||||
|
||||
// 7.25.3.4
|
||||
static inline int
|
||||
int
|
||||
cnd_signal(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
|
@ -131,7 +111,7 @@ cnd_signal(cnd_t *cond)
|
|||
}
|
||||
|
||||
// 7.25.3.5
|
||||
static inline int
|
||||
int
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
|
||||
{
|
||||
int rt;
|
||||
|
@ -147,7 +127,7 @@ cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
|
|||
}
|
||||
|
||||
// 7.25.3.6
|
||||
static inline int
|
||||
int
|
||||
cnd_wait(cnd_t *cond, mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -158,7 +138,7 @@ cnd_wait(cnd_t *cond, mtx_t *mtx)
|
|||
|
||||
/*-------------------- 7.25.4 Mutex functions --------------------*/
|
||||
// 7.25.4.1
|
||||
static inline void
|
||||
void
|
||||
mtx_destroy(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -192,7 +172,7 @@ int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
|
|||
#endif
|
||||
|
||||
// 7.25.4.2
|
||||
static inline int
|
||||
int
|
||||
mtx_init(mtx_t *mtx, int type)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
@ -216,21 +196,15 @@ mtx_init(mtx_t *mtx, int type)
|
|||
}
|
||||
|
||||
// 7.25.4.3
|
||||
static inline int
|
||||
int
|
||||
mtx_lock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mtx_trylock(mtx_t *mtx);
|
||||
|
||||
static inline void
|
||||
thrd_yield(void);
|
||||
|
||||
// 7.25.4.4
|
||||
static inline int
|
||||
int
|
||||
mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -259,7 +233,7 @@ mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
|||
}
|
||||
|
||||
// 7.25.4.5
|
||||
static inline int
|
||||
int
|
||||
mtx_trylock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -267,7 +241,7 @@ mtx_trylock(mtx_t *mtx)
|
|||
}
|
||||
|
||||
// 7.25.4.6
|
||||
static inline int
|
||||
int
|
||||
mtx_unlock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -277,7 +251,7 @@ mtx_unlock(mtx_t *mtx)
|
|||
|
||||
/*------------------- 7.25.5 Thread functions -------------------*/
|
||||
// 7.25.5.1
|
||||
static inline int
|
||||
int
|
||||
thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
|
||||
{
|
||||
struct impl_thrd_param *pack;
|
||||
|
@ -294,35 +268,36 @@ thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
|
|||
}
|
||||
|
||||
// 7.25.5.2
|
||||
static inline thrd_t
|
||||
thrd_t
|
||||
thrd_current(void)
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
// 7.25.5.3
|
||||
static inline int
|
||||
int
|
||||
thrd_detach(thrd_t thr)
|
||||
{
|
||||
return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.5.4
|
||||
static inline int
|
||||
int
|
||||
thrd_equal(thrd_t thr0, thrd_t thr1)
|
||||
{
|
||||
return pthread_equal(thr0, thr1);
|
||||
}
|
||||
|
||||
// 7.25.5.5
|
||||
static inline void
|
||||
_Noreturn
|
||||
void
|
||||
thrd_exit(int res)
|
||||
{
|
||||
pthread_exit((void*)(intptr_t)res);
|
||||
}
|
||||
|
||||
// 7.25.5.6
|
||||
static inline int
|
||||
int
|
||||
thrd_join(thrd_t thr, int *res)
|
||||
{
|
||||
void *code;
|
||||
|
@ -334,15 +309,15 @@ thrd_join(thrd_t thr, int *res)
|
|||
}
|
||||
|
||||
// 7.25.5.7
|
||||
static inline void
|
||||
int
|
||||
thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
|
||||
{
|
||||
assert(time_point != NULL);
|
||||
nanosleep(time_point, remaining);
|
||||
return nanosleep(time_point, remaining);
|
||||
}
|
||||
|
||||
// 7.25.5.8
|
||||
static inline void
|
||||
void
|
||||
thrd_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
|
@ -351,7 +326,7 @@ thrd_yield(void)
|
|||
|
||||
/*----------- 7.25.6 Thread-specific storage functions -----------*/
|
||||
// 7.25.6.1
|
||||
static inline int
|
||||
int
|
||||
tss_create(tss_t *key, tss_dtor_t dtor)
|
||||
{
|
||||
assert(key != NULL);
|
||||
|
@ -359,21 +334,21 @@ tss_create(tss_t *key, tss_dtor_t dtor)
|
|||
}
|
||||
|
||||
// 7.25.6.2
|
||||
static inline void
|
||||
void
|
||||
tss_delete(tss_t key)
|
||||
{
|
||||
pthread_key_delete(key);
|
||||
}
|
||||
|
||||
// 7.25.6.3
|
||||
static inline void *
|
||||
void *
|
||||
tss_get(tss_t key)
|
||||
{
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
// 7.25.6.4
|
||||
static inline int
|
||||
int
|
||||
tss_set(tss_t key, void *val)
|
||||
{
|
||||
return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;
|
|
@ -26,14 +26,19 @@
|
|||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef assert
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <process.h> // MSVCRT
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "c11/threads.h"
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
Configuration macro:
|
||||
|
||||
|
@ -54,50 +59,17 @@ Configuration macro:
|
|||
#endif
|
||||
#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#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
|
||||
|
||||
/*---------------------------- 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 CONDITION_VARIABLE 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);
|
||||
static_assert(sizeof(cnd_t) == sizeof(CONDITION_VARIABLE), "The size of cnd_t must equal to CONDITION_VARIABLE");
|
||||
static_assert(sizeof(thrd_t) == sizeof(HANDLE), "The size of thrd_t must equal to HANDLE");
|
||||
static_assert(sizeof(tss_t) == sizeof(DWORD), "The size of tss_t must equal to DWORD");
|
||||
static_assert(sizeof(mtx_t) == sizeof(CRITICAL_SECTION), "The size of mtx_t must equal to CRITICAL_SECTION");
|
||||
static_assert(sizeof(once_flag) == sizeof(INIT_ONCE), "The size of once_flag must equal to INIT_ONCE");
|
||||
|
||||
/*
|
||||
Implementation limits:
|
||||
|
@ -168,7 +140,7 @@ static int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void impl_tss_dtor_invoke()
|
||||
static void impl_tss_dtor_invoke(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
|
||||
|
@ -183,7 +155,7 @@ static void impl_tss_dtor_invoke()
|
|||
|
||||
/*--------------- 7.25.2 Initialization functions ---------------*/
|
||||
// 7.25.2.1
|
||||
static inline void
|
||||
void
|
||||
call_once(once_flag *flag, void (*func)(void))
|
||||
{
|
||||
assert(flag && func);
|
||||
|
@ -191,12 +163,12 @@ call_once(once_flag *flag, void (*func)(void))
|
|||
{
|
||||
struct impl_call_once_param param;
|
||||
param.func = func;
|
||||
InitOnceExecuteOnce(flag, impl_call_once_callback, (PVOID)¶m, NULL);
|
||||
InitOnceExecuteOnce((PINIT_ONCE)flag, impl_call_once_callback, (PVOID)¶m, NULL);
|
||||
}
|
||||
#else
|
||||
if (InterlockedCompareExchange(&flag->status, 1, 0) == 0) {
|
||||
if (InterlockedCompareExchangePointer((PVOID volatile *)&flag->status, (PVOID)1, (PVOID)0) == 0) {
|
||||
(func)();
|
||||
InterlockedExchange(&flag->status, 2);
|
||||
InterlockedExchangePointer((PVOID volatile *)&flag->status, (PVOID)2);
|
||||
} else {
|
||||
while (flag->status == 1) {
|
||||
// busy loop!
|
||||
|
@ -209,16 +181,16 @@ call_once(once_flag *flag, void (*func)(void))
|
|||
|
||||
/*------------- 7.25.3 Condition variable functions -------------*/
|
||||
// 7.25.3.1
|
||||
static inline int
|
||||
int
|
||||
cnd_broadcast(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
WakeAllConditionVariable(cond);
|
||||
WakeAllConditionVariable((PCONDITION_VARIABLE)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.3.2
|
||||
static inline void
|
||||
void
|
||||
cnd_destroy(cnd_t *cond)
|
||||
{
|
||||
(void)cond;
|
||||
|
@ -227,58 +199,58 @@ cnd_destroy(cnd_t *cond)
|
|||
}
|
||||
|
||||
// 7.25.3.3
|
||||
static inline int
|
||||
int
|
||||
cnd_init(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
InitializeConditionVariable(cond);
|
||||
InitializeConditionVariable((PCONDITION_VARIABLE)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.3.4
|
||||
static inline int
|
||||
int
|
||||
cnd_signal(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
WakeConditionVariable(cond);
|
||||
WakeConditionVariable((PCONDITION_VARIABLE)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.3.5
|
||||
static inline int
|
||||
int
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
assert(mtx != NULL);
|
||||
assert(abs_time != NULL);
|
||||
const DWORD timeout = impl_abs2relmsec(abs_time);
|
||||
if (SleepConditionVariableCS(cond, mtx, timeout))
|
||||
if (SleepConditionVariableCS((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mtx, timeout))
|
||||
return thrd_success;
|
||||
return (GetLastError() == ERROR_TIMEOUT) ? thrd_timedout : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.3.6
|
||||
static inline int
|
||||
int
|
||||
cnd_wait(cnd_t *cond, mtx_t *mtx)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
assert(mtx != NULL);
|
||||
SleepConditionVariableCS(cond, mtx, INFINITE);
|
||||
SleepConditionVariableCS((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mtx, INFINITE);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------- 7.25.4 Mutex functions --------------------*/
|
||||
// 7.25.4.1
|
||||
static inline void
|
||||
void
|
||||
mtx_destroy(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx);
|
||||
DeleteCriticalSection(mtx);
|
||||
DeleteCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
}
|
||||
|
||||
// 7.25.4.2
|
||||
static inline int
|
||||
int
|
||||
mtx_init(mtx_t *mtx, int type)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -287,21 +259,21 @@ mtx_init(mtx_t *mtx, int type)
|
|||
&& type != (mtx_timed|mtx_recursive)
|
||||
&& type != (mtx_try|mtx_recursive))
|
||||
return thrd_error;
|
||||
InitializeCriticalSection(mtx);
|
||||
InitializeCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.4.3
|
||||
static inline int
|
||||
int
|
||||
mtx_lock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
EnterCriticalSection(mtx);
|
||||
EnterCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.4.4
|
||||
static inline int
|
||||
int
|
||||
mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
|
@ -316,26 +288,26 @@ mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
|||
}
|
||||
|
||||
// 7.25.4.5
|
||||
static inline int
|
||||
int
|
||||
mtx_trylock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
return TryEnterCriticalSection(mtx) ? thrd_success : thrd_busy;
|
||||
return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy;
|
||||
}
|
||||
|
||||
// 7.25.4.6
|
||||
static inline int
|
||||
int
|
||||
mtx_unlock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
LeaveCriticalSection(mtx);
|
||||
LeaveCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
|
||||
/*------------------- 7.25.5 Thread functions -------------------*/
|
||||
// 7.25.5.1
|
||||
static inline int
|
||||
int
|
||||
thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
|
||||
{
|
||||
struct impl_thrd_param *pack;
|
||||
|
@ -397,7 +369,7 @@ thrd_current(void)
|
|||
#endif
|
||||
|
||||
// 7.25.5.3
|
||||
static inline int
|
||||
int
|
||||
thrd_detach(thrd_t thr)
|
||||
{
|
||||
CloseHandle(thr);
|
||||
|
@ -405,14 +377,15 @@ thrd_detach(thrd_t thr)
|
|||
}
|
||||
|
||||
// 7.25.5.4
|
||||
static inline int
|
||||
int
|
||||
thrd_equal(thrd_t thr0, thrd_t thr1)
|
||||
{
|
||||
return GetThreadId(thr0) == GetThreadId(thr1);
|
||||
}
|
||||
|
||||
// 7.25.5.5
|
||||
static inline void
|
||||
_Noreturn
|
||||
void
|
||||
thrd_exit(int res)
|
||||
{
|
||||
impl_tss_dtor_invoke();
|
||||
|
@ -420,7 +393,7 @@ thrd_exit(int res)
|
|||
}
|
||||
|
||||
// 7.25.5.6
|
||||
static inline int
|
||||
int
|
||||
thrd_join(thrd_t thr, int *res)
|
||||
{
|
||||
DWORD w, code;
|
||||
|
@ -439,17 +412,18 @@ thrd_join(thrd_t thr, int *res)
|
|||
}
|
||||
|
||||
// 7.25.5.7
|
||||
static inline void
|
||||
int
|
||||
thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
|
||||
{
|
||||
(void)remaining;
|
||||
assert(time_point);
|
||||
assert(!remaining); /* not implemented */
|
||||
Sleep((DWORD)impl_timespec2msec(time_point));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 7.25.5.8
|
||||
static inline void
|
||||
void
|
||||
thrd_yield(void)
|
||||
{
|
||||
SwitchToThread();
|
||||
|
@ -458,7 +432,7 @@ thrd_yield(void)
|
|||
|
||||
/*----------- 7.25.6 Thread-specific storage functions -----------*/
|
||||
// 7.25.6.1
|
||||
static inline int
|
||||
int
|
||||
tss_create(tss_t *key, tss_dtor_t dtor)
|
||||
{
|
||||
assert(key != NULL);
|
||||
|
@ -473,21 +447,21 @@ tss_create(tss_t *key, tss_dtor_t dtor)
|
|||
}
|
||||
|
||||
// 7.25.6.2
|
||||
static inline void
|
||||
void
|
||||
tss_delete(tss_t key)
|
||||
{
|
||||
TlsFree(key);
|
||||
}
|
||||
|
||||
// 7.25.6.3
|
||||
static inline void *
|
||||
void *
|
||||
tss_get(tss_t key)
|
||||
{
|
||||
return TlsGetValue(key);
|
||||
}
|
||||
|
||||
// 7.25.6.4
|
||||
static inline int
|
||||
int
|
||||
tss_set(tss_t key, void *val)
|
||||
{
|
||||
return TlsSetValue(key, val) ? thrd_success : thrd_error;
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2022 Yonggang Luo
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* C11 <threads.h> emulation library
|
||||
*/
|
||||
|
||||
#ifndef C11_THREADS_H_INCLUDED_
|
||||
#define C11_THREADS_H_INCLUDED_
|
||||
|
||||
#include "c11/time.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
# include <io.h> /* close */
|
||||
# include <process.h> /* _exit */
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
# include <pthread.h>
|
||||
# include <unistd.h> /* close, _exit */
|
||||
#else
|
||||
# error Not supported on this platform.
|
||||
#endif
|
||||
|
||||
/*---------------------------- macros ---------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*---------------------------- types ----------------------------*/
|
||||
typedef void (*tss_dtor_t)(void *);
|
||||
typedef int (*thrd_start_t)(void *);
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
typedef struct
|
||||
{
|
||||
void *Ptr;
|
||||
} cnd_t;
|
||||
typedef void *thrd_t;
|
||||
typedef unsigned long tss_t;
|
||||
typedef struct
|
||||
{
|
||||
void *DebugInfo;
|
||||
long LockCount;
|
||||
long RecursionCount;
|
||||
void *OwningThread;
|
||||
void *LockSemaphore;
|
||||
uintptr_t SpinCount;
|
||||
} mtx_t; /* Mock of CRITICAL_SECTION */
|
||||
typedef struct
|
||||
{
|
||||
volatile uintptr_t status;
|
||||
} once_flag;
|
||||
// FIXME: temporary non-standard hack to ease transition
|
||||
# define _MTX_INITIALIZER_NP {(void*)-1, -1, 0, 0, 0, 0}
|
||||
# define ONCE_FLAG_INIT {0}
|
||||
# define TSS_DTOR_ITERATIONS 1
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
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;
|
||||
// FIXME: temporary non-standard hack to ease transition
|
||||
# define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
|
||||
# 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
|
||||
#else
|
||||
# error Not supported on this platform.
|
||||
#endif
|
||||
|
||||
/*-------------------- enumeration constants --------------------*/
|
||||
enum
|
||||
{
|
||||
mtx_plain = 0,
|
||||
mtx_try = 1,
|
||||
mtx_timed = 2,
|
||||
mtx_recursive = 4
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
thrd_success = 0, // succeeded
|
||||
thrd_timedout, // timed out
|
||||
thrd_error, // failed
|
||||
thrd_busy, // resource busy
|
||||
thrd_nomem // out of memory
|
||||
};
|
||||
|
||||
/*-------------------------- functions --------------------------*/
|
||||
|
||||
void call_once(once_flag *, void (*)(void));
|
||||
int cnd_broadcast(cnd_t *);
|
||||
void cnd_destroy(cnd_t *);
|
||||
int cnd_init(cnd_t *);
|
||||
int cnd_signal(cnd_t *);
|
||||
int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx,
|
||||
const struct timespec *__restrict);
|
||||
int cnd_wait(cnd_t *, mtx_t *__mtx);
|
||||
void mtx_destroy(mtx_t *__mtx);
|
||||
int mtx_init(mtx_t *__mtx, int);
|
||||
int mtx_lock(mtx_t *__mtx);
|
||||
int mtx_timedlock(mtx_t *__restrict __mtx,
|
||||
const struct timespec *__restrict);
|
||||
int mtx_trylock(mtx_t *__mtx);
|
||||
int mtx_unlock(mtx_t *__mtx);
|
||||
int thrd_create(thrd_t *, thrd_start_t, void *);
|
||||
thrd_t thrd_current(void);
|
||||
int thrd_detach(thrd_t);
|
||||
int thrd_equal(thrd_t, thrd_t);
|
||||
#if defined(__cplusplus)
|
||||
[[ noreturn ]]
|
||||
#else
|
||||
_Noreturn
|
||||
#endif
|
||||
void thrd_exit(int);
|
||||
int thrd_join(thrd_t, int *);
|
||||
int thrd_sleep(const struct timespec *, struct timespec *);
|
||||
void thrd_yield(void);
|
||||
int tss_create(tss_t *, tss_dtor_t);
|
||||
void tss_delete(tss_t);
|
||||
void *tss_get(tss_t);
|
||||
int tss_set(tss_t, void *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* C11_THREADS_H_INCLUDED_ */
|
Loading…
Reference in New Issue