1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * C11 <threads.h> emulation library 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * (C) Copyright yohhoy 2012. 5bf215546Sopenharmony_ci * Distributed under the Boost Software License, Version 1.0. 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person or organization 8bf215546Sopenharmony_ci * obtaining a copy of the software and accompanying documentation covered by 9bf215546Sopenharmony_ci * this license (the "Software") to use, reproduce, display, distribute, 10bf215546Sopenharmony_ci * execute, and transmit the Software, and to prepare [[derivative work]]s of the 11bf215546Sopenharmony_ci * Software, and to permit third-parties to whom the Software is furnished to 12bf215546Sopenharmony_ci * do so, all subject to the following: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The copyright notices in the Software and this entire statement, including 15bf215546Sopenharmony_ci * the above license grant, this restriction and the following disclaimer, 16bf215546Sopenharmony_ci * must be included in all copies of the Software, in whole or in part, and 17bf215546Sopenharmony_ci * all derivative works of the Software, unless such copies or derivative 18bf215546Sopenharmony_ci * works are solely in the form of machine-executable object code generated by 19bf215546Sopenharmony_ci * a source language processor. 20bf215546Sopenharmony_ci * 21bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 24bf215546Sopenharmony_ci * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 25bf215546Sopenharmony_ci * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 26bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 28bf215546Sopenharmony_ci */ 29bf215546Sopenharmony_ci#include <stdlib.h> 30bf215546Sopenharmony_ci#include <assert.h> 31bf215546Sopenharmony_ci#include <limits.h> 32bf215546Sopenharmony_ci#include <errno.h> 33bf215546Sopenharmony_ci#include <unistd.h> 34bf215546Sopenharmony_ci#include <sched.h> 35bf215546Sopenharmony_ci#include <stdint.h> /* for intptr_t */ 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#include "c11/threads.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci/* 40bf215546Sopenharmony_ciConfiguration macro: 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci EMULATED_THREADS_USE_NATIVE_TIMEDLOCK 43bf215546Sopenharmony_ci Use pthread_mutex_timedlock() for `mtx_timedlock()' 44bf215546Sopenharmony_ci Otherwise use mtx_trylock() + *busy loop* emulation. 45bf215546Sopenharmony_ci*/ 46bf215546Sopenharmony_ci#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__NetBSD__) 47bf215546Sopenharmony_ci#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK 48bf215546Sopenharmony_ci#endif 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci/*---------------------------- types ----------------------------*/ 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci/* 53bf215546Sopenharmony_ciImplementation limits: 54bf215546Sopenharmony_ci - Conditionally emulation for "mutex with timeout" 55bf215546Sopenharmony_ci (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro) 56bf215546Sopenharmony_ci*/ 57bf215546Sopenharmony_cistruct impl_thrd_param { 58bf215546Sopenharmony_ci thrd_start_t func; 59bf215546Sopenharmony_ci void *arg; 60bf215546Sopenharmony_ci}; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic void * 63bf215546Sopenharmony_ciimpl_thrd_routine(void *p) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci struct impl_thrd_param pack = *((struct impl_thrd_param *)p); 66bf215546Sopenharmony_ci free(p); 67bf215546Sopenharmony_ci return (void*)(intptr_t)pack.func(pack.arg); 68bf215546Sopenharmony_ci} 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci/*--------------- 7.25.2 Initialization functions ---------------*/ 72bf215546Sopenharmony_ci// 7.25.2.1 73bf215546Sopenharmony_civoid 74bf215546Sopenharmony_cicall_once(once_flag *flag, void (*func)(void)) 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci pthread_once(flag, func); 77bf215546Sopenharmony_ci} 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci/*------------- 7.25.3 Condition variable functions -------------*/ 81bf215546Sopenharmony_ci// 7.25.3.1 82bf215546Sopenharmony_ciint 83bf215546Sopenharmony_cicnd_broadcast(cnd_t *cond) 84bf215546Sopenharmony_ci{ 85bf215546Sopenharmony_ci assert(cond != NULL); 86bf215546Sopenharmony_ci return (pthread_cond_broadcast(cond) == 0) ? thrd_success : thrd_error; 87bf215546Sopenharmony_ci} 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci// 7.25.3.2 90bf215546Sopenharmony_civoid 91bf215546Sopenharmony_cicnd_destroy(cnd_t *cond) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci assert(cond); 94bf215546Sopenharmony_ci pthread_cond_destroy(cond); 95bf215546Sopenharmony_ci} 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci// 7.25.3.3 98bf215546Sopenharmony_ciint 99bf215546Sopenharmony_cicnd_init(cnd_t *cond) 100bf215546Sopenharmony_ci{ 101bf215546Sopenharmony_ci assert(cond != NULL); 102bf215546Sopenharmony_ci return (pthread_cond_init(cond, NULL) == 0) ? thrd_success : thrd_error; 103bf215546Sopenharmony_ci} 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci// 7.25.3.4 106bf215546Sopenharmony_ciint 107bf215546Sopenharmony_cicnd_signal(cnd_t *cond) 108bf215546Sopenharmony_ci{ 109bf215546Sopenharmony_ci assert(cond != NULL); 110bf215546Sopenharmony_ci return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error; 111bf215546Sopenharmony_ci} 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci// 7.25.3.5 114bf215546Sopenharmony_ciint 115bf215546Sopenharmony_cicnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci int rt; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci assert(mtx != NULL); 120bf215546Sopenharmony_ci assert(cond != NULL); 121bf215546Sopenharmony_ci assert(abs_time != NULL); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci rt = pthread_cond_timedwait(cond, mtx, abs_time); 124bf215546Sopenharmony_ci if (rt == ETIMEDOUT) 125bf215546Sopenharmony_ci return thrd_timedout; 126bf215546Sopenharmony_ci return (rt == 0) ? thrd_success : thrd_error; 127bf215546Sopenharmony_ci} 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci// 7.25.3.6 130bf215546Sopenharmony_ciint 131bf215546Sopenharmony_cicnd_wait(cnd_t *cond, mtx_t *mtx) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci assert(mtx != NULL); 134bf215546Sopenharmony_ci assert(cond != NULL); 135bf215546Sopenharmony_ci return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success : thrd_error; 136bf215546Sopenharmony_ci} 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci/*-------------------- 7.25.4 Mutex functions --------------------*/ 140bf215546Sopenharmony_ci// 7.25.4.1 141bf215546Sopenharmony_civoid 142bf215546Sopenharmony_cimtx_destroy(mtx_t *mtx) 143bf215546Sopenharmony_ci{ 144bf215546Sopenharmony_ci assert(mtx != NULL); 145bf215546Sopenharmony_ci pthread_mutex_destroy(mtx); 146bf215546Sopenharmony_ci} 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci/* 149bf215546Sopenharmony_ci * XXX: Workaround when building with -O0 and without pthreads link. 150bf215546Sopenharmony_ci * 151bf215546Sopenharmony_ci * In such cases constant folding and dead code elimination won't be 152bf215546Sopenharmony_ci * available, thus the compiler will always add the pthread_mutexattr* 153bf215546Sopenharmony_ci * functions into the binary. As we try to link, we'll fail as the 154bf215546Sopenharmony_ci * symbols are unresolved. 155bf215546Sopenharmony_ci * 156bf215546Sopenharmony_ci * Ideally we'll enable the optimisations locally, yet that does not 157bf215546Sopenharmony_ci * seem to work. 158bf215546Sopenharmony_ci * 159bf215546Sopenharmony_ci * So the alternative workaround is to annotate the symbols as weak. 160bf215546Sopenharmony_ci * Thus the linker will be happy and things don't clash when building 161bf215546Sopenharmony_ci * with -O1 or greater. 162bf215546Sopenharmony_ci */ 163bf215546Sopenharmony_ci#if defined(HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__) 164bf215546Sopenharmony_ci__attribute__((weak)) 165bf215546Sopenharmony_ciint pthread_mutexattr_init(pthread_mutexattr_t *attr); 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci__attribute__((weak)) 168bf215546Sopenharmony_ciint pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci__attribute__((weak)) 171bf215546Sopenharmony_ciint pthread_mutexattr_destroy(pthread_mutexattr_t *attr); 172bf215546Sopenharmony_ci#endif 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci// 7.25.4.2 175bf215546Sopenharmony_ciint 176bf215546Sopenharmony_cimtx_init(mtx_t *mtx, int type) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci pthread_mutexattr_t attr; 179bf215546Sopenharmony_ci assert(mtx != NULL); 180bf215546Sopenharmony_ci if (type != mtx_plain && type != mtx_timed && type != mtx_try 181bf215546Sopenharmony_ci && type != (mtx_plain|mtx_recursive) 182bf215546Sopenharmony_ci && type != (mtx_timed|mtx_recursive) 183bf215546Sopenharmony_ci && type != (mtx_try|mtx_recursive)) 184bf215546Sopenharmony_ci return thrd_error; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci if ((type & mtx_recursive) == 0) { 187bf215546Sopenharmony_ci pthread_mutex_init(mtx, NULL); 188bf215546Sopenharmony_ci return thrd_success; 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci pthread_mutexattr_init(&attr); 192bf215546Sopenharmony_ci pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 193bf215546Sopenharmony_ci pthread_mutex_init(mtx, &attr); 194bf215546Sopenharmony_ci pthread_mutexattr_destroy(&attr); 195bf215546Sopenharmony_ci return thrd_success; 196bf215546Sopenharmony_ci} 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci// 7.25.4.3 199bf215546Sopenharmony_ciint 200bf215546Sopenharmony_cimtx_lock(mtx_t *mtx) 201bf215546Sopenharmony_ci{ 202bf215546Sopenharmony_ci assert(mtx != NULL); 203bf215546Sopenharmony_ci return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error; 204bf215546Sopenharmony_ci} 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci// 7.25.4.4 207bf215546Sopenharmony_ciint 208bf215546Sopenharmony_cimtx_timedlock(mtx_t *mtx, const struct timespec *ts) 209bf215546Sopenharmony_ci{ 210bf215546Sopenharmony_ci assert(mtx != NULL); 211bf215546Sopenharmony_ci assert(ts != NULL); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci { 214bf215546Sopenharmony_ci#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK 215bf215546Sopenharmony_ci int rt; 216bf215546Sopenharmony_ci rt = pthread_mutex_timedlock(mtx, ts); 217bf215546Sopenharmony_ci if (rt == 0) 218bf215546Sopenharmony_ci return thrd_success; 219bf215546Sopenharmony_ci return (rt == ETIMEDOUT) ? thrd_timedout : thrd_error; 220bf215546Sopenharmony_ci#else 221bf215546Sopenharmony_ci time_t expire = time(NULL); 222bf215546Sopenharmony_ci expire += ts->tv_sec; 223bf215546Sopenharmony_ci while (mtx_trylock(mtx) != thrd_success) { 224bf215546Sopenharmony_ci time_t now = time(NULL); 225bf215546Sopenharmony_ci if (expire < now) 226bf215546Sopenharmony_ci return thrd_timedout; 227bf215546Sopenharmony_ci // busy loop! 228bf215546Sopenharmony_ci thrd_yield(); 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci return thrd_success; 231bf215546Sopenharmony_ci#endif 232bf215546Sopenharmony_ci } 233bf215546Sopenharmony_ci} 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci// 7.25.4.5 236bf215546Sopenharmony_ciint 237bf215546Sopenharmony_cimtx_trylock(mtx_t *mtx) 238bf215546Sopenharmony_ci{ 239bf215546Sopenharmony_ci assert(mtx != NULL); 240bf215546Sopenharmony_ci return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci// 7.25.4.6 244bf215546Sopenharmony_ciint 245bf215546Sopenharmony_cimtx_unlock(mtx_t *mtx) 246bf215546Sopenharmony_ci{ 247bf215546Sopenharmony_ci assert(mtx != NULL); 248bf215546Sopenharmony_ci return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error; 249bf215546Sopenharmony_ci} 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci/*------------------- 7.25.5 Thread functions -------------------*/ 253bf215546Sopenharmony_ci// 7.25.5.1 254bf215546Sopenharmony_ciint 255bf215546Sopenharmony_cithrd_create(thrd_t *thr, thrd_start_t func, void *arg) 256bf215546Sopenharmony_ci{ 257bf215546Sopenharmony_ci struct impl_thrd_param *pack; 258bf215546Sopenharmony_ci assert(thr != NULL); 259bf215546Sopenharmony_ci pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param)); 260bf215546Sopenharmony_ci if (!pack) return thrd_nomem; 261bf215546Sopenharmony_ci pack->func = func; 262bf215546Sopenharmony_ci pack->arg = arg; 263bf215546Sopenharmony_ci if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) { 264bf215546Sopenharmony_ci free(pack); 265bf215546Sopenharmony_ci return thrd_error; 266bf215546Sopenharmony_ci } 267bf215546Sopenharmony_ci return thrd_success; 268bf215546Sopenharmony_ci} 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci// 7.25.5.2 271bf215546Sopenharmony_cithrd_t 272bf215546Sopenharmony_cithrd_current(void) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci return pthread_self(); 275bf215546Sopenharmony_ci} 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci// 7.25.5.3 278bf215546Sopenharmony_ciint 279bf215546Sopenharmony_cithrd_detach(thrd_t thr) 280bf215546Sopenharmony_ci{ 281bf215546Sopenharmony_ci return (pthread_detach(thr) == 0) ? thrd_success : thrd_error; 282bf215546Sopenharmony_ci} 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci// 7.25.5.4 285bf215546Sopenharmony_ciint 286bf215546Sopenharmony_cithrd_equal(thrd_t thr0, thrd_t thr1) 287bf215546Sopenharmony_ci{ 288bf215546Sopenharmony_ci return pthread_equal(thr0, thr1); 289bf215546Sopenharmony_ci} 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci// 7.25.5.5 292bf215546Sopenharmony_ci_Noreturn 293bf215546Sopenharmony_civoid 294bf215546Sopenharmony_cithrd_exit(int res) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci pthread_exit((void*)(intptr_t)res); 297bf215546Sopenharmony_ci} 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci// 7.25.5.6 300bf215546Sopenharmony_ciint 301bf215546Sopenharmony_cithrd_join(thrd_t thr, int *res) 302bf215546Sopenharmony_ci{ 303bf215546Sopenharmony_ci void *code; 304bf215546Sopenharmony_ci if (pthread_join(thr, &code) != 0) 305bf215546Sopenharmony_ci return thrd_error; 306bf215546Sopenharmony_ci if (res) 307bf215546Sopenharmony_ci *res = (int)(intptr_t)code; 308bf215546Sopenharmony_ci return thrd_success; 309bf215546Sopenharmony_ci} 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci// 7.25.5.7 312bf215546Sopenharmony_ciint 313bf215546Sopenharmony_cithrd_sleep(const struct timespec *time_point, struct timespec *remaining) 314bf215546Sopenharmony_ci{ 315bf215546Sopenharmony_ci assert(time_point != NULL); 316bf215546Sopenharmony_ci return nanosleep(time_point, remaining); 317bf215546Sopenharmony_ci} 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci// 7.25.5.8 320bf215546Sopenharmony_civoid 321bf215546Sopenharmony_cithrd_yield(void) 322bf215546Sopenharmony_ci{ 323bf215546Sopenharmony_ci sched_yield(); 324bf215546Sopenharmony_ci} 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci/*----------- 7.25.6 Thread-specific storage functions -----------*/ 328bf215546Sopenharmony_ci// 7.25.6.1 329bf215546Sopenharmony_ciint 330bf215546Sopenharmony_citss_create(tss_t *key, tss_dtor_t dtor) 331bf215546Sopenharmony_ci{ 332bf215546Sopenharmony_ci assert(key != NULL); 333bf215546Sopenharmony_ci return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error; 334bf215546Sopenharmony_ci} 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci// 7.25.6.2 337bf215546Sopenharmony_civoid 338bf215546Sopenharmony_citss_delete(tss_t key) 339bf215546Sopenharmony_ci{ 340bf215546Sopenharmony_ci pthread_key_delete(key); 341bf215546Sopenharmony_ci} 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci// 7.25.6.3 344bf215546Sopenharmony_civoid * 345bf215546Sopenharmony_citss_get(tss_t key) 346bf215546Sopenharmony_ci{ 347bf215546Sopenharmony_ci return pthread_getspecific(key); 348bf215546Sopenharmony_ci} 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci// 7.25.6.4 351bf215546Sopenharmony_ciint 352bf215546Sopenharmony_citss_set(tss_t key, void *val) 353bf215546Sopenharmony_ci{ 354bf215546Sopenharmony_ci return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error; 355bf215546Sopenharmony_ci} 356