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 93 extern "C" { 94 #endif 95 96 /*---------------------------- types ----------------------------*/ 97 typedef void (*tss_dtor_t)(void *); 98 typedef int (*thrd_start_t)(void *); 99 100 #if defined(_WIN32) && !defined(__CYGWIN__) 101 typedef struct 102 { 103 void *Ptr; 104 } cnd_t; 105 typedef void *thrd_t; 106 typedef unsigned long tss_t; 107 typedef 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 */ 116 typedef 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) 125 typedef pthread_cond_t cnd_t; 126 typedef pthread_t thrd_t; 127 typedef pthread_key_t tss_t; 128 typedef pthread_mutex_t mtx_t; 129 typedef 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 --------------------*/ 143 enum 144 { 145 mtx_plain = 0, 146 mtx_try = 1, 147 mtx_timed = 2, 148 mtx_recursive = 4 149 }; 150 151 enum 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 162 void call_once(once_flag *, void (*)(void)); 163 int cnd_broadcast(cnd_t *); 164 void cnd_destroy(cnd_t *); 165 int cnd_init(cnd_t *); 166 int cnd_signal(cnd_t *); 167 int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx, 168 const struct timespec *__restrict); 169 int cnd_wait(cnd_t *, mtx_t *__mtx); 170 void mtx_destroy(mtx_t *__mtx); 171 int mtx_init(mtx_t *__mtx, int); 172 int mtx_lock(mtx_t *__mtx); 173 int mtx_timedlock(mtx_t *__restrict __mtx, 174 const struct timespec *__restrict); 175 int mtx_trylock(mtx_t *__mtx); 176 int mtx_unlock(mtx_t *__mtx); 177 int thrd_create(thrd_t *, thrd_start_t, void *); 178 thrd_t thrd_current(void); 179 int thrd_detach(thrd_t); 180 int thrd_equal(thrd_t, thrd_t); 181 #if defined(__cplusplus) 182 [[ noreturn ]] 183 #else 184 _Noreturn 185 #endif 186 void thrd_exit(int); 187 int thrd_join(thrd_t, int *); 188 int thrd_sleep(const struct timespec *, struct timespec *); 189 void thrd_yield(void); 190 int tss_create(tss_t *, tss_dtor_t); 191 void tss_delete(tss_t); 192 void *tss_get(tss_t); 193 int 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