22 #ifndef P99_THREADS_POSIX_H
23 #define P99_THREADS_POSIX_H 1
62 #define P99_ONCE_FLAG_INIT { { 0 } }
64 #ifndef PTHREAD_DESTRUCTOR_ITERATIONS
65 # warning "definition of PTHREAD_DESTRUCTOR_ITERATIONS is missing"
72 # define TSS_DTOR_ITERATIONS 1
74 # define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
95 typedef struct p00_thrd p00_thrd;
131 atomic_flag p00_detached;
132 unsigned p00_foreign;
215 void thrd_yield(
void) {
224 #define P00_THRD_LOCAL P99_THREAD_LOCAL(p00_thrd_local)
227 _Atomic(
size_t) p00_foreign_nb;
230 p00_thrd ** p00_foreign_tab;
233 void p00_foreign_cleanup(
void) {
234 size_t p00_foreign = atomic_load_explicit(&p00_foreign_nb, memory_order_consume);
235 p00_thrd ** p00_thrd = p00_foreign_tab;
240 atomic_thread_fence(memory_order_seq_cst);
241 for (
size_t p00_i = 0; p00_i < p00_foreign; ++p00_i) {
242 if (!pthread_equal(p00_thrd[p00_i]->p00_id, pthread_self()))
243 fputs(
"found foreign thread\n", stderr);
244 free(p00_thrd[p00_i]);
256 thrd_t thrd_current(
void) {
257 p00_thrd * p00_loc = P00_THRD_LOCAL;
259 size_t p00_nb = atomic_fetch_add_explicit(&p00_foreign_nb, 1, memory_order_acq_rel);
260 if (!p00_nb) atexit(p00_foreign_cleanup);
261 if ((p00_nb^(p00_nb-1)) == (p00_nb+(p00_nb-1))) {
262 p00_foreign_tab = realloc(p00_foreign_tab,
sizeof(p00_thrd*[2*(p00_nb+1)]));
264 p00_loc = malloc(
sizeof *p00_loc);
265 p00_foreign_tab[p00_nb] = p00_loc;
266 *p00_loc = (p00_thrd) {
267 .p00_id = pthread_self(),
268 .p00_foreign = p00_nb + 1,
270 P00_THRD_LOCAL = p00_loc;
273 unsigned char raw[16];
275 unsigned long long ull;
276 }
id = { .raw = { 0 } };
277 id.thrd = p00_loc->p00_id;
278 fprintf(stderr,
"foreign thread %llu is %zu\n",
id.ull, p00_nb + 1);
292 int thrd_equal(thrd_t p00_thr0, thrd_t p00_thr1) {
307 int cnd_broadcast(cnd_t *p00_cond) {
315 void cnd_destroy(cnd_t *p00_cond) {
329 int cnd_init(cnd_t *p00_cond) {
346 int cnd_signal(cnd_t *p00_cond) {
350 #if (POSIX_TIMEOUTS > 0) || !defined(POSIX_TIMEOUTS)
362 int cnd_timedwait(cnd_t *restrict p00_cond, mtx_t *restrict p00_mtx,
const struct timespec *restrict p00_ts) {
363 int p00_ret = pthread_cond_timedwait(&
P99_ENCP(p00_cond), &
P99_ENCP(p00_mtx), p00_ts);
381 int cnd_wait(cnd_t *p00_cond, mtx_t *p00_mtx) {
391 void mtx_destroy(mtx_t *p00_mtx) {
406 int mtx_init(mtx_t *p00_mtx,
int p00_type) {
408 pthread_mutexattr_t p00_attr;
409 int p00_ret = pthread_mutexattr_init(&p00_attr);
412 case mtx_normal: p00_ret = PTHREAD_MUTEX_NORMAL;
break;
414 case mtx_recursive: p00_ret = PTHREAD_MUTEX_RECURSIVE;
break;
417 p00_ret = pthread_mutexattr_settype(&p00_attr, p00_ret);
435 int mtx_lock(mtx_t *p00_mtx) {
439 #if (POSIX_TIMEOUTS > 0) || !defined(POSIX_TIMEOUTS)
451 int mtx_timedlock(mtx_t *restrict p00_mtx,
const struct timespec *restrict p00_ts) {
452 int p00_ret = pthread_mutex_timedlock(&
P99_ENCP(p00_mtx), p00_ts);
470 int mtx_trylock(mtx_t *p00_mtx) {
471 int p00_ret = pthread_mutex_trylock(&
P99_ENCP(p00_mtx));
486 int mtx_unlock(mtx_t *p00_mtx) {
492 void * p00_thrd_create(
void* p00_context);
503 int thrd_create(thrd_t *p00_thr,
thrd_start_t p00_func,
void *p00_arg) {
504 p00_thrd * p00_cntxt = malloc(
sizeof *p00_cntxt);
506 *p00_cntxt = (p00_thrd
const) {
509 .p00_func = p00_func,
513 .p00_detached = ATOMIC_FLAG_INIT,
515 int p00_ret = pthread_create(&p00_cntxt->p00_id, 0, p00_thrd_create, p00_cntxt);
536 int thrd_detach(thrd_t p00_thr) {
541 if (atomic_flag_test_and_set_explicit(&
P99_ENC(p00_thr)->p00_detached, memory_order_acq_rel)) {
559 void thrd_exit(
int p00_res) {
560 p00_thrd * p00_cntxt = P00_THRD_LOCAL;
562 if (!p00_cntxt->p00_foreign) {
563 p00_cntxt->p00_ret = p00_res;
564 longjmp(p00_cntxt->p00_ovrl.p00_jmp, 1);
573 "P99: We are exiting a foreign thread (main?) with error code %d\n"
574 "P99: There is no consistent way we can transmit that code to the environment\n",
580 #if defined(P99_INTERCEPT_MAIN) || defined(P00_DOXYGEN)
603 struct p00_threads_main_arg {
609 int p00_threads_main(
void* p00_arg) {
610 struct p00_threads_main_arg *p00_a = p00_arg;
611 int p00_argc = p00_a->p00_argc;
612 char**p00_argv = p00_a->p00_argv;
620 fprintf(stderr,
"exiting main thread with code %d", p00_ret);
627 struct p00_threads_main_arg * p00_arg = malloc(
sizeof *p00_arg);
628 *p00_arg = (
struct p00_threads_main_arg) {
629 .p00_argc = *p00_argc,
630 .p00_argv = *p00_argv,
632 thrd_create(&
id, p00_threads_main, p00_arg);
638 #define main p99_threads_main
650 int thrd_join(thrd_t p00_thr,
int *p00_res) {
653 if (p00_res) *p00_res =
P99_ENC(p00_thr)->p00_ret;
668 int thrd_sleep(
const struct timespec *p00_duration,
struct timespec *p00_remaining) {
670 int p00_ret = nanosleep(p00_duration, p00_remaining);
685 void * p00_thrd_create(
void* p00_context) {
686 p00_thrd * p00_cntxt = p00_context;
687 P00_THRD_LOCAL = p00_cntxt;
689 thrd_start_t p00_func = p00_cntxt->p00_ovrl.p00_init.p00_func;
690 void * p00_arg = p00_cntxt->p00_ovrl.p00_init.p00_arg;
691 if (!setjmp(p00_cntxt->p00_ovrl.p00_jmp)) {
692 p00_cntxt->p00_ret = p00_func(p00_arg);
694 if (atomic_flag_test_and_set_explicit(&p00_cntxt->p00_detached, memory_order_acq_rel)) {