1/* 2 * C11 <threads.h> emulation library 3 * 4 * (C) Copyright yohhoy 2012. 5 * Copyright 2022 Yonggang Luo 6 * Distributed under the Boost Software License, Version 1.0. 7 * 8 * Permission is hereby granted, free of charge, to any person or organization 9 * obtaining a copy of the software and accompanying documentation covered by 10 * this license (the "Software") to use, reproduce, display, distribute, 11 * execute, and transmit the Software, and to prepare [[derivative work]]s of the 12 * Software, and to permit third-parties to whom the Software is furnished to 13 * do so, all subject to the following: 14 * 15 * The copyright notices in the Software and this entire statement, including 16 * the above license grant, this restriction and the following disclaimer, 17 * must be included in all copies of the Software, in whole or in part, and 18 * all derivative works of the Software, unless such copies or derivative 19 * works are solely in the form of machine-executable object code generated by 20 * a source language processor. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 25 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 26 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 27 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 * DEALINGS IN THE SOFTWARE. 29 */ 30 31#ifndef C11_THREADS_H_INCLUDED_ 32#define C11_THREADS_H_INCLUDED_ 33 34#include "c11/time.h" 35 36#include <errno.h> 37#include <limits.h> 38#include <stdlib.h> 39 40#if defined(_WIN32) && !defined(__CYGWIN__) 41# include <io.h> /* close */ 42# include <process.h> /* _exit */ 43#elif defined(HAVE_PTHREAD) 44# include <pthread.h> 45# include <unistd.h> /* close, _exit */ 46#else 47# error Not supported on this platform. 48#endif 49 50#if defined(HAVE_THRD_CREATE) 51#include <threads.h> 52 53#if defined(ANDROID) 54/* Currently, only Android are verified that it's thrd_t are typedef of pthread_t 55 * So we can define _MTX_INITIALIZER_NP to PTHREAD_MUTEX_INITIALIZER 56 * FIXME: temporary non-standard hack to ease transition 57 */ 58# define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER 59#else 60#error Can not define _MTX_INITIALIZER_NP properly for this platform 61#endif 62#else 63 64/*---------------------------- macros ---------------------------*/ 65 66#ifndef _Thread_local 67# if defined(__cplusplus) 68 /* C++11 doesn't need `_Thread_local` keyword or macro */ 69# elif !defined(__STDC_NO_THREADS__) 70 /* threads are optional in C11, _Thread_local present in this condition */ 71# elif defined(_MSC_VER) 72# define _Thread_local __declspec(thread) 73# elif defined(__GNUC__) 74# define _Thread_local __thread 75# else 76 /* Leave _Thread_local undefined so that use of _Thread_local would not promote 77 * to a non-thread-local global variable 78 */ 79# endif 80#endif 81 82#if !defined(__cplusplus) 83 /* 84 * C11 thread_local() macro 85 * C++11 and above already have thread_local keyword 86 */ 87# ifndef thread_local 88# define thread_local _Thread_local 89# endif 90#endif 91 92#ifdef __cplusplus 93extern "C" { 94#endif 95 96/*---------------------------- types ----------------------------*/ 97typedef void (*tss_dtor_t)(void *); 98typedef int (*thrd_start_t)(void *); 99 100#if defined(_WIN32) && !defined(__CYGWIN__) 101typedef struct 102{ 103 void *Ptr; 104} cnd_t; 105typedef void *thrd_t; 106typedef unsigned long tss_t; 107typedef struct 108{ 109 void *DebugInfo; 110 long LockCount; 111 long RecursionCount; 112 void *OwningThread; 113 void *LockSemaphore; 114 uintptr_t SpinCount; 115} mtx_t; /* Mock of CRITICAL_SECTION */ 116typedef struct 117{ 118 volatile uintptr_t status; 119} once_flag; 120// FIXME: temporary non-standard hack to ease transition 121# define _MTX_INITIALIZER_NP {(void*)-1, -1, 0, 0, 0, 0} 122# define ONCE_FLAG_INIT {0} 123# define TSS_DTOR_ITERATIONS 1 124#elif defined(HAVE_PTHREAD) 125typedef pthread_cond_t cnd_t; 126typedef pthread_t thrd_t; 127typedef pthread_key_t tss_t; 128typedef pthread_mutex_t mtx_t; 129typedef pthread_once_t once_flag; 130// FIXME: temporary non-standard hack to ease transition 131# define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER 132# define ONCE_FLAG_INIT PTHREAD_ONCE_INIT 133# ifdef INIT_ONCE_STATIC_INIT 134# define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS 135# else 136# define TSS_DTOR_ITERATIONS 1 // assume TSS dtor MAY be called at least once. 137# endif 138#else 139# error Not supported on this platform. 140#endif 141 142/*-------------------- enumeration constants --------------------*/ 143enum 144{ 145 mtx_plain = 0, 146 mtx_try = 1, 147 mtx_timed = 2, 148 mtx_recursive = 4 149}; 150 151enum 152{ 153 thrd_success = 0, // succeeded 154 thrd_timedout, // timed out 155 thrd_error, // failed 156 thrd_busy, // resource busy 157 thrd_nomem // out of memory 158}; 159 160/*-------------------------- functions --------------------------*/ 161 162void call_once(once_flag *, void (*)(void)); 163int cnd_broadcast(cnd_t *); 164void cnd_destroy(cnd_t *); 165int cnd_init(cnd_t *); 166int cnd_signal(cnd_t *); 167int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx, 168 const struct timespec *__restrict); 169int cnd_wait(cnd_t *, mtx_t *__mtx); 170void mtx_destroy(mtx_t *__mtx); 171int mtx_init(mtx_t *__mtx, int); 172int mtx_lock(mtx_t *__mtx); 173int mtx_timedlock(mtx_t *__restrict __mtx, 174 const struct timespec *__restrict); 175int mtx_trylock(mtx_t *__mtx); 176int mtx_unlock(mtx_t *__mtx); 177int thrd_create(thrd_t *, thrd_start_t, void *); 178thrd_t thrd_current(void); 179int thrd_detach(thrd_t); 180int thrd_equal(thrd_t, thrd_t); 181#if defined(__cplusplus) 182[[ noreturn ]] 183#else 184_Noreturn 185#endif 186void thrd_exit(int); 187int thrd_join(thrd_t, int *); 188int thrd_sleep(const struct timespec *, struct timespec *); 189void thrd_yield(void); 190int tss_create(tss_t *, tss_dtor_t); 191void tss_delete(tss_t); 192void *tss_get(tss_t); 193int tss_set(tss_t, void *); 194 195#ifdef __cplusplus 196} 197#endif 198 199#endif /* HAVE_THRD_CREATE */ 200 201#endif /* C11_THREADS_H_INCLUDED_ */ 202