summaryrefslogtreecommitdiff
path: root/lib/libc/thread/thrd_join.c
blob: 7ec38c4a694138d176291929ff48e48ce42a8f35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <__thread.h>
#include <libc/futex.h>
#include <stdatomic.h>
#include <sys/mman.h>
#include <threads.h>

int thrd_join(thrd_t thr, int *res)
{
	struct __thread_self *tcb = (struct __thread_self *)thr;
	if (tcb == NULL)
		return thrd_error;

	int state = atomic_load_explicit(&tcb->state, memory_order_seq_cst);
	if (state == THREAD_STATE_DETACHED)
		return thrd_error; // Cannot join a detached thread

	while (atomic_load_explicit(&tcb->state, memory_order_seq_cst) != THREAD_STATE_EXITED) {
		int cur = atomic_load_explicit(&tcb->state, memory_order_seq_cst);
		int r = __futex_wait((volatile int *)&tcb->state, cur);
		if (r < 0)
			return thrd_error;
	}

	if (res) {
		*res = tcb->res;
	}

	atomic_store_explicit(&tcb->state, THREAD_STATE_JOINABLE, memory_order_seq_cst);
	__futex_wake((volatile int *)&tcb->state, 1);

	if (tcb->map_base == NULL || tcb->map_size == 0)
		return thrd_error;

	munmap(tcb->map_base, tcb->map_size);

	return thrd_success;
}