#ifndef _THREADS_H #define _THREADS_H #include #include enum { thrd_success = 0, thrd_busy = EBUSY, thrd_error = EINVAL, thrd_nomem = ENOMEM, thrd_timedout = ETIMEDOUT, }; enum { mtx_plain = 0, mtx_recursive = PTHREAD_MUTEX_RECURSIVE, mtx_check = PTHREAD_MUTEX_ERRORCHECK, // all mutexes are timed, here. so this is a no-op mtx_timed = 0, }; _Static_assert((mtx_plain | mtx_recursive | mtx_check | mtx_timed) == 3, "This implementation only works on top of musl"); #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT #define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS typedef pthread_cond_t cnd_t; typedef pthread_mutex_t mtx_t; typedef pthread_once_t once_flag; typedef pthread_t thrd_t; typedef pthread_key_t tss_t; typedef int (*thrd_start_t)(void*); typedef void (*tss_dtor_t)(void*); #define thread_local _Thread_local /* Don't create just additional symbols for the simple reason that the return type of the POSIX and C11 functions are different. */ int __pthread_once(once_flag *, void (*)(void)); // void call_once(once_flag *flag, void (*func)(void)); #define _call_once(FL, FU) (void)__pthread_once((FL), (FU)) #define call_once _call_once _Noreturn void __pthread_exit(void *); // _Noreturn void thrd_exit(int res); #define _thrd_exit(RES) (__pthread_exit((void*)(intptr_t)(RES))) #define thrd_exit _thrd_exit int __pthread_cond_destroy(cnd_t *cond); // void cnd_destroy(cnd_t *cond); #define _cnd_destroy(CND) (void)__pthread_cond_destroy((CND)) #define cnd_destroy _cnd_destroy void __pthread_mutex_destroy(mtx_t *mtx); // void mtx_destroy(mtx_t *mtx); #define _mtx_destroy(MTX) (void)__pthread_mutex_destroy((MTX)) #define mtx_destroy _mtx_destroy int __pthread_mutex_unlock(mtx_t *mtx); // int mtx_unlock(mtx_t *mtx); #define _mtx_unlock(MTX) (__pthread_mutex_unlock((MTX)) ? thrd_error : thrd_success) #define mtx_unlock _mtx_unlock int __pthread_key_delete(tss_t key); // void tss_delete(tss_t key); #define _tss_delete(KEY) (void)__pthread_key_delete((KEY)) #define tss_delete _tss_delete /* Best of all worlds, these are just weak aliases */ int cnd_broadcast(cnd_t *); // pthread_cond_broadcast int cnd_signal(cnd_t *); // pthread_cond_signal int cnd_timedwait(cnd_t *restrict, // pthread_cond_timedwait mtx_t *restrict, const struct timespec *restrict); int cnd_wait(cnd_t *cond, mtx_t *mtx); // pthread_cond_wait int mtx_lock(mtx_t *); // pthread_mutex_lock int mtx_timedlock(mtx_t *restrict, // pthread_mutex_timedlock const struct timespec *restrict); int mtx_trylock(mtx_t *); // pthread_mutex_trylock thrd_t thrd_current(void); // pthread_self int thrd_equal(thrd_t, thrd_t); // pthread_equal int thrd_detach(thrd_t); // pthread_detach int tss_create(tss_t *, tss_dtor_t); // pthread_key_create void *tss_get(tss_t); // pthread_getspecific int tss_set(tss_t, void *); // pthread_setspecific /* specialized implementations */ int cnd_init(cnd_t *); int mtx_init(mtx_t *, int); // reimplemented because of different calling convention // shaves of a lot of code for attributes and cancelation int thrd_create(thrd_t *, thrd_start_t, void *); // reimplemented because of different calling convention int thrd_join(thrd_t, int *); // reimplemented because of different return value convention int thrd_sleep(const struct timespec *, struct timespec *); // reimplemented because of different return type void thrd_yield(void); #endif