mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-10-31 10:58:03 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -0,0 +1,3 @@
|
||||
[*.{c,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
@@ -0,0 +1,32 @@
|
||||
# Copyright © 2022 Yonggang Luo
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
inc_util_c11 = [include_directories('../..')]
|
||||
|
||||
files_mesa_util_c11 = files(
|
||||
'time.c',
|
||||
)
|
||||
|
||||
if with_c11_threads
|
||||
# no need implement c11 threads
|
||||
elif host_machine.system() == 'windows'
|
||||
files_mesa_util_c11 += 'threads_win32.c'
|
||||
files_mesa_util_c11 += 'threads_win32_tls_callback.cpp'
|
||||
else
|
||||
files_mesa_util_c11 += 'threads_posix.c'
|
||||
endif
|
||||
|
||||
_libmesa_util_c11 = static_library(
|
||||
'mesa_util_c11',
|
||||
[files_mesa_util_c11],
|
||||
include_directories : inc_util_c11,
|
||||
c_args : [c_msvc_compat_args],
|
||||
gnu_symbol_visibility : 'hidden',
|
||||
build_by_default : false
|
||||
)
|
||||
|
||||
idep_mesautilc11 = declare_dependency(
|
||||
link_with : _libmesa_util_c11,
|
||||
include_directories : inc_util_c11,
|
||||
dependencies : [dep_clock, dep_thread, dep_atomic, dep_m, dep_valgrind],
|
||||
)
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSL-1.0
|
||||
* Copyright yohhoy 2012.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <stdint.h> /* for intptr_t */
|
||||
|
||||
#include "c11/threads.h"
|
||||
|
||||
/*
|
||||
Configuration macro:
|
||||
|
||||
EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
|
||||
Use pthread_mutex_timedlock() for `mtx_timedlock()'
|
||||
Otherwise use mtx_trylock() + *busy loop* emulation.
|
||||
*/
|
||||
#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__NetBSD__)
|
||||
#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
|
||||
#endif
|
||||
|
||||
/*---------------------------- types ----------------------------*/
|
||||
|
||||
/*
|
||||
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 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
|
||||
#ifndef __once_flag_defined
|
||||
void
|
||||
call_once(once_flag *flag, void (*func)(void))
|
||||
{
|
||||
pthread_once(flag, func);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*------------- 7.25.3 Condition variable functions -------------*/
|
||||
// 7.25.3.1
|
||||
int
|
||||
cnd_broadcast(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
return (pthread_cond_broadcast(cond) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.3.2
|
||||
void
|
||||
cnd_destroy(cnd_t *cond)
|
||||
{
|
||||
assert(cond);
|
||||
pthread_cond_destroy(cond);
|
||||
}
|
||||
|
||||
// 7.25.3.3
|
||||
int
|
||||
cnd_init(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
return (pthread_cond_init(cond, NULL) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.3.4
|
||||
int
|
||||
cnd_signal(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.3.5
|
||||
int
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
|
||||
{
|
||||
int rt;
|
||||
|
||||
assert(mtx != NULL);
|
||||
assert(cond != NULL);
|
||||
assert(abs_time != NULL);
|
||||
|
||||
rt = pthread_cond_timedwait(cond, mtx, abs_time);
|
||||
if (rt == ETIMEDOUT)
|
||||
return thrd_timedout;
|
||||
return (rt == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.3.6
|
||||
int
|
||||
cnd_wait(cnd_t *cond, mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
assert(cond != NULL);
|
||||
return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------- 7.25.4 Mutex functions --------------------*/
|
||||
// 7.25.4.1
|
||||
void
|
||||
mtx_destroy(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
pthread_mutex_destroy(mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Workaround when building with -O0 and without pthreads link.
|
||||
*
|
||||
* In such cases constant folding and dead code elimination won't be
|
||||
* available, thus the compiler will always add the pthread_mutexattr*
|
||||
* functions into the binary. As we try to link, we'll fail as the
|
||||
* symbols are unresolved.
|
||||
*
|
||||
* Ideally we'll enable the optimisations locally, yet that does not
|
||||
* seem to work.
|
||||
*
|
||||
* So the alternative workaround is to annotate the symbols as weak.
|
||||
* Thus the linker will be happy and things don't clash when building
|
||||
* with -O1 or greater.
|
||||
*/
|
||||
#if defined(HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__)
|
||||
__attribute__((weak))
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
|
||||
|
||||
__attribute__((weak))
|
||||
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
|
||||
|
||||
__attribute__((weak))
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
|
||||
#endif
|
||||
|
||||
// 7.25.4.2
|
||||
int
|
||||
mtx_init(mtx_t *mtx, int type)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
assert(mtx != NULL);
|
||||
if (type != mtx_plain && type != mtx_timed
|
||||
&& type != (mtx_plain|mtx_recursive)
|
||||
&& type != (mtx_timed|mtx_recursive))
|
||||
return thrd_error;
|
||||
|
||||
if ((type & mtx_recursive) == 0) {
|
||||
pthread_mutex_init(mtx, NULL);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(mtx, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.4.3
|
||||
int
|
||||
mtx_lock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
static int
|
||||
threads_timespec_compare(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
if (a->tv_sec < b->tv_sec) {
|
||||
return -1;
|
||||
} else if (a->tv_sec > b->tv_sec) {
|
||||
return 1;
|
||||
} else if (a->tv_nsec < b->tv_nsec) {
|
||||
return -1;
|
||||
} else if (a->tv_nsec > b->tv_nsec) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 7.25.4.4
|
||||
int
|
||||
mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
assert(ts != NULL);
|
||||
|
||||
{
|
||||
#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
|
||||
int rt;
|
||||
rt = pthread_mutex_timedlock(mtx, ts);
|
||||
if (rt == 0)
|
||||
return thrd_success;
|
||||
return (rt == ETIMEDOUT) ? thrd_timedout : thrd_error;
|
||||
#else
|
||||
while (mtx_trylock(mtx) != thrd_success) {
|
||||
struct timespec now;
|
||||
if (timespec_get(&now, TIME_UTC) != TIME_UTC) {
|
||||
return thrd_error;
|
||||
}
|
||||
if (threads_timespec_compare(ts, &now) < 0)
|
||||
return thrd_timedout;
|
||||
// busy loop!
|
||||
thrd_yield();
|
||||
}
|
||||
return thrd_success;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// 7.25.4.5
|
||||
int
|
||||
mtx_trylock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
|
||||
}
|
||||
|
||||
// 7.25.4.6
|
||||
int
|
||||
mtx_unlock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
|
||||
/*------------------- 7.25.5 Thread functions -------------------*/
|
||||
// 7.25.5.1
|
||||
int
|
||||
thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
|
||||
{
|
||||
struct impl_thrd_param *pack;
|
||||
assert(thr != NULL);
|
||||
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
|
||||
thrd_t
|
||||
thrd_current(void)
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
// 7.25.5.3
|
||||
int
|
||||
thrd_detach(thrd_t thr)
|
||||
{
|
||||
return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.5.4
|
||||
int
|
||||
thrd_equal(thrd_t thr0, thrd_t thr1)
|
||||
{
|
||||
return pthread_equal(thr0, thr1);
|
||||
}
|
||||
|
||||
// 7.25.5.5
|
||||
_Noreturn
|
||||
void
|
||||
thrd_exit(int res)
|
||||
{
|
||||
pthread_exit((void*)(intptr_t)res);
|
||||
}
|
||||
|
||||
// 7.25.5.6
|
||||
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
|
||||
int
|
||||
thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
|
||||
{
|
||||
assert(time_point != NULL);
|
||||
return nanosleep(time_point, remaining);
|
||||
}
|
||||
|
||||
// 7.25.5.8
|
||||
void
|
||||
thrd_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
/*----------- 7.25.6 Thread-specific storage functions -----------*/
|
||||
// 7.25.6.1
|
||||
int
|
||||
tss_create(tss_t *key, tss_dtor_t dtor)
|
||||
{
|
||||
assert(key != NULL);
|
||||
return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.6.2
|
||||
void
|
||||
tss_delete(tss_t key)
|
||||
{
|
||||
pthread_key_delete(key);
|
||||
}
|
||||
|
||||
// 7.25.6.3
|
||||
void *
|
||||
tss_get(tss_t key)
|
||||
{
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
// 7.25.6.4
|
||||
int
|
||||
tss_set(tss_t key, void *val)
|
||||
{
|
||||
return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSL-1.0
|
||||
* Copyright yohhoy 2012.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <process.h> // MSVCRT
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "c11/threads.h"
|
||||
|
||||
#include "threads_win32.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
Configuration macro:
|
||||
EMULATED_THREADS_TSS_DTOR_SLOTNUM
|
||||
Max registerable TSS dtor number.
|
||||
*/
|
||||
|
||||
#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE
|
||||
|
||||
|
||||
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:
|
||||
- Emulated `mtx_timelock()' with mtx_trylock() + *busy loop*
|
||||
*/
|
||||
|
||||
struct impl_thrd_param {
|
||||
thrd_start_t func;
|
||||
void *arg;
|
||||
thrd_t thrd;
|
||||
};
|
||||
|
||||
struct thrd_state {
|
||||
thrd_t thrd;
|
||||
bool handle_need_close;
|
||||
};
|
||||
|
||||
static thread_local struct thrd_state impl_current_thread = { 0 };
|
||||
|
||||
static unsigned __stdcall impl_thrd_routine(void *p)
|
||||
{
|
||||
struct impl_thrd_param *pack_p = (struct impl_thrd_param *)p;
|
||||
struct impl_thrd_param pack;
|
||||
int code;
|
||||
impl_current_thread.thrd = pack_p->thrd;
|
||||
impl_current_thread.handle_need_close = false;
|
||||
memcpy(&pack, pack_p, sizeof(struct impl_thrd_param));
|
||||
free(p);
|
||||
code = pack.func(pack.arg);
|
||||
return (unsigned)code;
|
||||
}
|
||||
|
||||
static time_t impl_timespec2msec(const struct timespec *ts)
|
||||
{
|
||||
return (ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L);
|
||||
}
|
||||
|
||||
static DWORD impl_abs2relmsec(const struct timespec *abs_time)
|
||||
{
|
||||
const time_t abs_ms = impl_timespec2msec(abs_time);
|
||||
struct timespec now;
|
||||
timespec_get(&now, TIME_UTC);
|
||||
const time_t now_ms = impl_timespec2msec(&now);
|
||||
const DWORD rel_ms = (abs_ms > now_ms) ? (DWORD)(abs_ms - now_ms) : 0;
|
||||
return rel_ms;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(void)
|
||||
{
|
||||
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
|
||||
void
|
||||
call_once(once_flag *flag, void (*func)(void))
|
||||
{
|
||||
assert(flag && func);
|
||||
struct impl_call_once_param param;
|
||||
param.func = func;
|
||||
InitOnceExecuteOnce((PINIT_ONCE)flag, impl_call_once_callback, (PVOID)¶m, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*------------- 7.25.3 Condition variable functions -------------*/
|
||||
// 7.25.3.1
|
||||
int
|
||||
cnd_broadcast(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
WakeAllConditionVariable((PCONDITION_VARIABLE)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.3.2
|
||||
void
|
||||
cnd_destroy(cnd_t *cond)
|
||||
{
|
||||
(void)cond;
|
||||
assert(cond != NULL);
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// 7.25.3.3
|
||||
int
|
||||
cnd_init(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
InitializeConditionVariable((PCONDITION_VARIABLE)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.3.4
|
||||
int
|
||||
cnd_signal(cnd_t *cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
WakeConditionVariable((PCONDITION_VARIABLE)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.3.5
|
||||
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((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mtx, timeout))
|
||||
return thrd_success;
|
||||
return (GetLastError() == ERROR_TIMEOUT) ? thrd_timedout : thrd_error;
|
||||
}
|
||||
|
||||
// 7.25.3.6
|
||||
int
|
||||
cnd_wait(cnd_t *cond, mtx_t *mtx)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
assert(mtx != NULL);
|
||||
SleepConditionVariableCS((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mtx, INFINITE);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------- 7.25.4 Mutex functions --------------------*/
|
||||
// 7.25.4.1
|
||||
void
|
||||
mtx_destroy(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx);
|
||||
DeleteCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
}
|
||||
|
||||
// 7.25.4.2
|
||||
int
|
||||
mtx_init(mtx_t *mtx, int type)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
if (type != mtx_plain && type != mtx_timed
|
||||
&& type != (mtx_plain|mtx_recursive)
|
||||
&& type != (mtx_timed|mtx_recursive))
|
||||
return thrd_error;
|
||||
InitializeCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.4.3
|
||||
int
|
||||
mtx_lock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
EnterCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.4.4
|
||||
int
|
||||
mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
assert(ts != NULL);
|
||||
while (mtx_trylock(mtx) != thrd_success) {
|
||||
if (impl_abs2relmsec(ts) == 0)
|
||||
return thrd_timedout;
|
||||
// busy loop!
|
||||
thrd_yield();
|
||||
}
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.4.5
|
||||
int
|
||||
mtx_trylock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy;
|
||||
}
|
||||
|
||||
// 7.25.4.6
|
||||
int
|
||||
mtx_unlock(mtx_t *mtx)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
LeaveCriticalSection((PCRITICAL_SECTION)mtx);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
void
|
||||
__threads_win32_tls_callback(void)
|
||||
{
|
||||
struct thrd_state *state = &impl_current_thread;
|
||||
impl_tss_dtor_invoke();
|
||||
if (state->handle_need_close) {
|
||||
state->handle_need_close = false;
|
||||
CloseHandle(state->thrd.handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------- 7.25.5 Thread functions -------------------*/
|
||||
// 7.25.5.1
|
||||
int
|
||||
thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
|
||||
{
|
||||
struct impl_thrd_param *pack;
|
||||
uintptr_t handle;
|
||||
assert(thr != NULL);
|
||||
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, CREATE_SUSPENDED, NULL);
|
||||
if (handle == 0) {
|
||||
free(pack);
|
||||
if (errno == EAGAIN || errno == EACCES)
|
||||
return thrd_nomem;
|
||||
return thrd_error;
|
||||
}
|
||||
thr->handle = (void*)handle;
|
||||
pack->thrd = *thr;
|
||||
ResumeThread((HANDLE)handle);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.5.2
|
||||
thrd_t
|
||||
thrd_current(void)
|
||||
{
|
||||
/* GetCurrentThread() returns a pseudo-handle, which we need
|
||||
* to pass to DuplicateHandle(). Only the resulting handle can be used
|
||||
* from other threads.
|
||||
*
|
||||
* Note that neither handle can be compared to the one by thread_create.
|
||||
* Only the thread IDs - as returned by GetThreadId() and GetCurrentThreadId()
|
||||
* can be compared directly.
|
||||
*
|
||||
* Other potential solutions would be:
|
||||
* - define thrd_t as a thread Ids, but this would mean we'd need to OpenThread for many operations
|
||||
* - use malloc'ed memory for thrd_t. This would imply using TLS for current thread.
|
||||
*
|
||||
* Neither is particularly nice.
|
||||
*
|
||||
* Life would be much easier if C11 threads had different abstractions for
|
||||
* threads and thread IDs, just like C++11 threads does...
|
||||
*/
|
||||
struct thrd_state *state = &impl_current_thread;
|
||||
if (state->thrd.handle == NULL)
|
||||
{
|
||||
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
|
||||
&(state->thrd.handle), 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
abort();
|
||||
}
|
||||
state->handle_need_close = true;
|
||||
}
|
||||
return state->thrd;
|
||||
}
|
||||
|
||||
// 7.25.5.3
|
||||
int
|
||||
thrd_detach(thrd_t thr)
|
||||
{
|
||||
CloseHandle(thr.handle);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.5.4
|
||||
int
|
||||
thrd_equal(thrd_t thr0, thrd_t thr1)
|
||||
{
|
||||
return GetThreadId(thr0.handle) == GetThreadId(thr1.handle);
|
||||
}
|
||||
|
||||
// 7.25.5.5
|
||||
_Noreturn
|
||||
void
|
||||
thrd_exit(int res)
|
||||
{
|
||||
_endthreadex((unsigned)res);
|
||||
}
|
||||
|
||||
// 7.25.5.6
|
||||
int
|
||||
thrd_join(thrd_t thr, int *res)
|
||||
{
|
||||
DWORD w, code;
|
||||
if (thr.handle == NULL) {
|
||||
return thrd_error;
|
||||
}
|
||||
w = WaitForSingleObject(thr.handle, INFINITE);
|
||||
if (w != WAIT_OBJECT_0)
|
||||
return thrd_error;
|
||||
if (res) {
|
||||
if (!GetExitCodeThread(thr.handle, &code)) {
|
||||
CloseHandle(thr.handle);
|
||||
return thrd_error;
|
||||
}
|
||||
*res = (int)code;
|
||||
}
|
||||
CloseHandle(thr.handle);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// 7.25.5.7
|
||||
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
|
||||
void
|
||||
thrd_yield(void)
|
||||
{
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
|
||||
/*----------- 7.25.6 Thread-specific storage functions -----------*/
|
||||
// 7.25.6.1
|
||||
int
|
||||
tss_create(tss_t *key, tss_dtor_t dtor)
|
||||
{
|
||||
assert(key != NULL);
|
||||
*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
|
||||
void
|
||||
tss_delete(tss_t key)
|
||||
{
|
||||
TlsFree(key);
|
||||
}
|
||||
|
||||
// 7.25.6.3
|
||||
void *
|
||||
tss_get(tss_t key)
|
||||
{
|
||||
return TlsGetValue(key);
|
||||
}
|
||||
|
||||
// 7.25.6.4
|
||||
int
|
||||
tss_set(tss_t key, void *val)
|
||||
{
|
||||
return TlsSetValue(key, val) ? thrd_success : thrd_error;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2022 Yonggang Luo
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef C11_IMPL_THREADS_WIN32_H_
|
||||
#define C11_IMPL_THREADS_WIN32_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void __threads_win32_tls_callback(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2022 Yonggang Luo
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "threads_win32.h"
|
||||
|
||||
struct tls_callback
|
||||
{
|
||||
tls_callback()
|
||||
{
|
||||
}
|
||||
~tls_callback()
|
||||
{
|
||||
__threads_win32_tls_callback();
|
||||
}
|
||||
};
|
||||
static thread_local tls_callback tls_callback_instance;
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* C11 <time.h> implementation
|
||||
*
|
||||
* (C) Copyright yohhoy 2012.
|
||||
* Copyright 2022 Yonggang Luo
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "c11/time.h"
|
||||
|
||||
#ifdef _TIMESPEC_GET_NEED_IMPL
|
||||
|
||||
#if defined(_WIN32) && !defined(HAVE_PTHREAD)
|
||||
|
||||
#include "c11/threads.h"
|
||||
#include <windows.h>
|
||||
|
||||
static LARGE_INTEGER frequency;
|
||||
|
||||
static
|
||||
void
|
||||
c23_timespec_get_init(void)
|
||||
{
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
}
|
||||
|
||||
int
|
||||
c23_timespec_get(struct timespec *ts, int base)
|
||||
{
|
||||
/* difference between 1970 and 1601 */
|
||||
#define _TIMESPEC_IMPL_UNIX_EPOCH_IN_TICKS 116444736000000000ull
|
||||
/* 1 tick is 100 nanoseconds */
|
||||
#define _TIMESPEC_IMPL_TICKS_PER_SECONDS 10000000ull
|
||||
if (!ts)
|
||||
return 0;
|
||||
if (base == TIME_UTC) {
|
||||
FILETIME ft;
|
||||
ULARGE_INTEGER date;
|
||||
LONGLONG ticks;
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
date.HighPart = ft.dwHighDateTime;
|
||||
date.LowPart = ft.dwLowDateTime;
|
||||
ticks = (LONGLONG)(date.QuadPart - _TIMESPEC_IMPL_UNIX_EPOCH_IN_TICKS);
|
||||
ts->tv_sec = ticks / _TIMESPEC_IMPL_TICKS_PER_SECONDS;
|
||||
ts->tv_nsec = (ticks % _TIMESPEC_IMPL_TICKS_PER_SECONDS) * 100;
|
||||
return base;
|
||||
} else if (base == TIME_MONOTONIC || base == TIME_MONOTONIC_RAW) {
|
||||
if (frequency.QuadPart == 0) {
|
||||
static once_flag once = ONCE_FLAG_INIT;
|
||||
call_once(&once, c23_timespec_get_init);
|
||||
}
|
||||
if (frequency.QuadPart != 0) {
|
||||
LARGE_INTEGER now;
|
||||
LONGLONG sec;
|
||||
LONGLONG nsec;
|
||||
QueryPerformanceCounter(&now);
|
||||
sec = now.QuadPart / frequency.QuadPart;
|
||||
nsec = (now.QuadPart - sec * frequency.QuadPart)
|
||||
* 1000000000UL / frequency.QuadPart;
|
||||
ts->tv_sec = (time_t)sec;
|
||||
ts->tv_nsec = (long)nsec;
|
||||
return base;
|
||||
}
|
||||
/* Otherwise timespec_get with TIME_MONOTONIC or TIME_MONOTONIC_RAW failed */
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
#undef _TIMESPEC_IMPL_UNIX_EPOCH_IN_TICKS
|
||||
#undef _TIMESPEC_IMPL_TICKS_PER_SECONDS
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int c23_timespec_get(struct timespec *ts, int base)
|
||||
{
|
||||
if (!ts)
|
||||
return 0;
|
||||
switch (base)
|
||||
{
|
||||
case TIME_UTC:
|
||||
if (clock_gettime(CLOCK_REALTIME, ts) == 0)
|
||||
return base;
|
||||
break;
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
case TIME_MONOTONIC:
|
||||
if (clock_gettime(CLOCK_MONOTONIC, ts) == 0)
|
||||
return base;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CLOCK_PROCESS_CPUTIME_ID
|
||||
case TIME_ACTIVE:
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ts) == 0)
|
||||
return base;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CLOCK_THREAD_CPUTIME_ID
|
||||
case TIME_THREAD_ACTIVE:
|
||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts) == 0)
|
||||
return base;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
case TIME_MONOTONIC_RAW:
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, ts) == 0)
|
||||
return base;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !HAVE_TIMESPEC_GET */
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* C11 <threads.h> emulation library
|
||||
*
|
||||
* (C) Copyright yohhoy 2012.
|
||||
* Copyright 2022 Yonggang Luo
|
||||
* 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 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(HAVE_PTHREAD)
|
||||
# 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
|
||||
|
||||
#if defined(HAVE_THRD_CREATE)
|
||||
#include <threads.h>
|
||||
#else
|
||||
|
||||
/*---------------------------- macros ---------------------------*/
|
||||
|
||||
#ifndef _Thread_local
|
||||
# if defined(__cplusplus)
|
||||
/* C++11 doesn't need `_Thread_local` keyword or macro */
|
||||
# elif !defined(__STDC_NO_THREADS__)
|
||||
/* threads are optional in C11, _Thread_local present in this condition */
|
||||
# elif defined(_MSC_VER)
|
||||
# define _Thread_local __declspec(thread)
|
||||
# elif defined(__GNUC__)
|
||||
# define _Thread_local __thread
|
||||
# else
|
||||
/* Leave _Thread_local undefined so that use of _Thread_local would not promote
|
||||
* to a non-thread-local global variable
|
||||
*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
/*
|
||||
* C11 thread_local() macro
|
||||
* C++11 and above already have thread_local keyword
|
||||
*/
|
||||
# ifndef thread_local
|
||||
# define thread_local _Thread_local
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*---------------------------- types ----------------------------*/
|
||||
typedef void (*tss_dtor_t)(void *);
|
||||
typedef int (*thrd_start_t)(void *);
|
||||
|
||||
#if defined(_WIN32) && !defined(HAVE_PTHREAD)
|
||||
typedef struct
|
||||
{
|
||||
void *Ptr;
|
||||
} cnd_t;
|
||||
/* Define thrd_t as struct type intentionally for avoid use of thrd_t as pointer type */
|
||||
typedef struct
|
||||
{
|
||||
void *handle;
|
||||
} 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;
|
||||
# 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;
|
||||
#ifndef __once_flag_defined
|
||||
typedef pthread_once_t once_flag;
|
||||
# define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
|
||||
#endif
|
||||
# ifdef PTHREAD_DESTRUCTOR_ITERATIONS
|
||||
# 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 = 0x1,
|
||||
mtx_recursive = 0x2,
|
||||
mtx_timed = 0x4,
|
||||
};
|
||||
|
||||
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 /* HAVE_THRD_CREATE */
|
||||
|
||||
#endif /* C11_THREADS_H_INCLUDED_ */
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2022 Yonggang Luo
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* C11 <time.h> emulation library
|
||||
*/
|
||||
|
||||
#ifndef C11_TIME_H_INCLUDED_
|
||||
#define C11_TIME_H_INCLUDED_
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/*---------------------------- macros ---------------------------*/
|
||||
|
||||
/* Refer to https://htmlpreview.github.io/?https://icube-forge.unistra.fr/icps/c23-library/-/raw/main/README.html#time_monotonic-time_active-time_thread_active */
|
||||
#if defined(TIME_UTC) && \
|
||||
defined(TIME_MONOTONIC) && \
|
||||
defined(TIME_ACTIVE) && \
|
||||
defined(TIME_THREAD_ACTIVE) && \
|
||||
defined(TIME_MONOTONIC_RAW)
|
||||
/* all needed time base is implemented */
|
||||
#else
|
||||
#define _TIMESPEC_GET_NEED_IMPL
|
||||
#endif
|
||||
|
||||
#ifdef _TIMESPEC_GET_NEED_IMPL
|
||||
#undef TIME_UTC
|
||||
#undef TIME_MONOTONIC
|
||||
#undef TIME_ACTIVE
|
||||
#undef TIME_THREAD_ACTIVE
|
||||
#undef TIME_MONOTONIC_RAW
|
||||
/* c11 */
|
||||
#define TIME_UTC 1
|
||||
/* c23 */
|
||||
#define TIME_MONOTONIC 2
|
||||
#define TIME_ACTIVE 3
|
||||
#define TIME_THREAD_ACTIVE 4
|
||||
#define TIME_MONOTONIC_RAW 5
|
||||
#define timespec_get c23_timespec_get
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*---------------------------- types ----------------------------*/
|
||||
|
||||
/*
|
||||
* On MINGW `struct timespec` present but `timespec_get` may not present;
|
||||
* On MSVC `struct timespec` and `timespec_get` present at the same time;
|
||||
* So detecting `HAVE_STRUCT_TIMESPEC` in meson script dynamically.
|
||||
*/
|
||||
#ifndef HAVE_STRUCT_TIMESPEC
|
||||
struct timespec
|
||||
{
|
||||
time_t tv_sec; // Seconds - >= 0
|
||||
long tv_nsec; // Nanoseconds - [0, 999999999]
|
||||
};
|
||||
#endif
|
||||
|
||||
/*-------------------------- functions --------------------------*/
|
||||
|
||||
#if defined(_TIMESPEC_GET_NEED_IMPL)
|
||||
#define _TIMESPEC_GET_NEED_DECL
|
||||
#elif defined(__APPLE__) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
/* On macOS, the guard for declaration of timespec_get is by
|
||||
* (defined(__cplusplus) && __cplusplus >= 201703L),
|
||||
* fix the declaration for C++14 and lower here
|
||||
*/
|
||||
#define _TIMESPEC_GET_NEED_DECL
|
||||
#endif
|
||||
|
||||
#ifdef _TIMESPEC_GET_NEED_DECL
|
||||
/*-------------------- 7.25.7 Time functions --------------------*/
|
||||
// 7.25.6.1
|
||||
int
|
||||
timespec_get(struct timespec *ts, int base);
|
||||
#undef _TIMESPEC_GET_NEED_DECL
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* C11_TIME_H_INCLUDED_ */
|
||||
Reference in new issue
Block a user