Path: blob/21.2-virgl/include/c11/threads_posix.h
4545 views
/*1* C11 <threads.h> emulation library2*3* (C) Copyright yohhoy 2012.4* Distributed under the Boost Software License, Version 1.0.5*6* Permission is hereby granted, free of charge, to any person or organization7* obtaining a copy of the software and accompanying documentation covered by8* this license (the "Software") to use, reproduce, display, distribute,9* execute, and transmit the Software, and to prepare [[derivative work]]s of the10* Software, and to permit third-parties to whom the Software is furnished to11* do so, all subject to the following:12*13* The copyright notices in the Software and this entire statement, including14* the above license grant, this restriction and the following disclaimer,15* must be included in all copies of the Software, in whole or in part, and16* all derivative works of the Software, unless such copies or derivative17* works are solely in the form of machine-executable object code generated by18* a source language processor.19*20* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR21* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,22* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT23* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE24* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,25* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER26* DEALINGS IN THE SOFTWARE.27*/28#include <stdlib.h>29#ifndef assert30#include <assert.h>31#endif32#include <limits.h>33#include <errno.h>34#include <unistd.h>35#include <sched.h>36#include <stdint.h> /* for intptr_t */3738/*39Configuration macro:4041EMULATED_THREADS_USE_NATIVE_TIMEDLOCK42Use pthread_mutex_timedlock() for `mtx_timedlock()'43Otherwise use mtx_trylock() + *busy loop* emulation.44*/45#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__NetBSD__)46#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK47#endif484950#include <pthread.h>5152/*---------------------------- macros ----------------------------*/53#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT54#ifdef INIT_ONCE_STATIC_INIT55#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS56#else57#define TSS_DTOR_ITERATIONS 1 // assume TSS dtor MAY be called at least once.58#endif5960// FIXME: temporary non-standard hack to ease transition61#define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER6263/*---------------------------- types ----------------------------*/64typedef pthread_cond_t cnd_t;65typedef pthread_t thrd_t;66typedef pthread_key_t tss_t;67typedef pthread_mutex_t mtx_t;68typedef pthread_once_t once_flag;697071/*72Implementation limits:73- Conditionally emulation for "mutex with timeout"74(see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro)75*/76struct impl_thrd_param {77thrd_start_t func;78void *arg;79};8081static inline void *82impl_thrd_routine(void *p)83{84struct impl_thrd_param pack = *((struct impl_thrd_param *)p);85free(p);86return (void*)(intptr_t)pack.func(pack.arg);87}888990/*--------------- 7.25.2 Initialization functions ---------------*/91// 7.25.2.192static inline void93call_once(once_flag *flag, void (*func)(void))94{95pthread_once(flag, func);96}979899/*------------- 7.25.3 Condition variable functions -------------*/100// 7.25.3.1101static inline int102cnd_broadcast(cnd_t *cond)103{104assert(cond != NULL);105return (pthread_cond_broadcast(cond) == 0) ? thrd_success : thrd_error;106}107108// 7.25.3.2109static inline void110cnd_destroy(cnd_t *cond)111{112assert(cond);113pthread_cond_destroy(cond);114}115116// 7.25.3.3117static inline int118cnd_init(cnd_t *cond)119{120assert(cond != NULL);121return (pthread_cond_init(cond, NULL) == 0) ? thrd_success : thrd_error;122}123124// 7.25.3.4125static inline int126cnd_signal(cnd_t *cond)127{128assert(cond != NULL);129return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error;130}131132// 7.25.3.5133static inline int134cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)135{136int rt;137138assert(mtx != NULL);139assert(cond != NULL);140assert(abs_time != NULL);141142rt = pthread_cond_timedwait(cond, mtx, abs_time);143if (rt == ETIMEDOUT)144return thrd_busy;145return (rt == 0) ? thrd_success : thrd_error;146}147148// 7.25.3.6149static inline int150cnd_wait(cnd_t *cond, mtx_t *mtx)151{152assert(mtx != NULL);153assert(cond != NULL);154return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success : thrd_error;155}156157158/*-------------------- 7.25.4 Mutex functions --------------------*/159// 7.25.4.1160static inline void161mtx_destroy(mtx_t *mtx)162{163assert(mtx != NULL);164pthread_mutex_destroy(mtx);165}166167/*168* XXX: Workaround when building with -O0 and without pthreads link.169*170* In such cases constant folding and dead code elimination won't be171* available, thus the compiler will always add the pthread_mutexattr*172* functions into the binary. As we try to link, we'll fail as the173* symbols are unresolved.174*175* Ideally we'll enable the optimisations locally, yet that does not176* seem to work.177*178* So the alternative workaround is to annotate the symbols as weak.179* Thus the linker will be happy and things don't clash when building180* with -O1 or greater.181*/182#if defined(HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__)183__attribute__((weak))184int pthread_mutexattr_init(pthread_mutexattr_t *attr);185186__attribute__((weak))187int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);188189__attribute__((weak))190int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);191#endif192193// 7.25.4.2194static inline int195mtx_init(mtx_t *mtx, int type)196{197pthread_mutexattr_t attr;198assert(mtx != NULL);199if (type != mtx_plain && type != mtx_timed && type != mtx_try200&& type != (mtx_plain|mtx_recursive)201&& type != (mtx_timed|mtx_recursive)202&& type != (mtx_try|mtx_recursive))203return thrd_error;204205if ((type & mtx_recursive) == 0) {206pthread_mutex_init(mtx, NULL);207return thrd_success;208}209210pthread_mutexattr_init(&attr);211pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);212pthread_mutex_init(mtx, &attr);213pthread_mutexattr_destroy(&attr);214return thrd_success;215}216217// 7.25.4.3218static inline int219mtx_lock(mtx_t *mtx)220{221assert(mtx != NULL);222return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error;223}224225static inline int226mtx_trylock(mtx_t *mtx);227228static inline void229thrd_yield(void);230231// 7.25.4.4232static inline int233mtx_timedlock(mtx_t *mtx, const struct timespec *ts)234{235assert(mtx != NULL);236assert(ts != NULL);237238{239#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK240int rt;241rt = pthread_mutex_timedlock(mtx, ts);242if (rt == 0)243return thrd_success;244return (rt == ETIMEDOUT) ? thrd_busy : thrd_error;245#else246time_t expire = time(NULL);247expire += ts->tv_sec;248while (mtx_trylock(mtx) != thrd_success) {249time_t now = time(NULL);250if (expire < now)251return thrd_busy;252// busy loop!253thrd_yield();254}255return thrd_success;256#endif257}258}259260// 7.25.4.5261static inline int262mtx_trylock(mtx_t *mtx)263{264assert(mtx != NULL);265return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;266}267268// 7.25.4.6269static inline int270mtx_unlock(mtx_t *mtx)271{272assert(mtx != NULL);273return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error;274}275276277/*------------------- 7.25.5 Thread functions -------------------*/278// 7.25.5.1279static inline int280thrd_create(thrd_t *thr, thrd_start_t func, void *arg)281{282struct impl_thrd_param *pack;283assert(thr != NULL);284pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param));285if (!pack) return thrd_nomem;286pack->func = func;287pack->arg = arg;288if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) {289free(pack);290return thrd_error;291}292return thrd_success;293}294295// 7.25.5.2296static inline thrd_t297thrd_current(void)298{299return pthread_self();300}301302// 7.25.5.3303static inline int304thrd_detach(thrd_t thr)305{306return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;307}308309// 7.25.5.4310static inline int311thrd_equal(thrd_t thr0, thrd_t thr1)312{313return pthread_equal(thr0, thr1);314}315316// 7.25.5.5317static inline void318thrd_exit(int res)319{320pthread_exit((void*)(intptr_t)res);321}322323// 7.25.5.6324static inline int325thrd_join(thrd_t thr, int *res)326{327void *code;328if (pthread_join(thr, &code) != 0)329return thrd_error;330if (res)331*res = (int)(intptr_t)code;332return thrd_success;333}334335// 7.25.5.7336static inline void337thrd_sleep(const struct timespec *time_point, struct timespec *remaining)338{339assert(time_point != NULL);340nanosleep(time_point, remaining);341}342343// 7.25.5.8344static inline void345thrd_yield(void)346{347sched_yield();348}349350351/*----------- 7.25.6 Thread-specific storage functions -----------*/352// 7.25.6.1353static inline int354tss_create(tss_t *key, tss_dtor_t dtor)355{356assert(key != NULL);357return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error;358}359360// 7.25.6.2361static inline void362tss_delete(tss_t key)363{364pthread_key_delete(key);365}366367// 7.25.6.3368static inline void *369tss_get(tss_t key)370{371return pthread_getspecific(key);372}373374// 7.25.6.4375static inline int376tss_set(tss_t key, void *val)377{378return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;379}380381382/*-------------------- 7.25.7 Time functions --------------------*/383// 7.25.6.1384#ifndef HAVE_TIMESPEC_GET385static inline int386timespec_get(struct timespec *ts, int base)387{388if (!ts) return 0;389if (base == TIME_UTC) {390clock_gettime(CLOCK_REALTIME, ts);391return base;392}393return 0;394}395#endif396397398