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:
Yonggang Luo 2022-02-19 13:19:08 +08:00 committed by Marge Bot
parent b7773fd105
commit e6392fcf3d
7 changed files with 226 additions and 202 deletions

View File

@ -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 | | |
+-----------------+------------------------+-----------------------------+

View File

@ -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_ */

View File

@ -1,3 +1,3 @@
[*.h]
[*.{c,h}]
indent_style = space
indent_size = 4

View File

@ -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],

View File

@ -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;

View File

@ -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)&param, NULL);
InitOnceExecuteOnce((PINIT_ONCE)flag, impl_call_once_callback, (PVOID)&param, 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;

136
src/c11/threads.h Normal file
View File

@ -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_ */