xref: /aosp_15_r20/external/musl/src/time/timer_create.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #include <time.h>
2*c9945492SAndroid Build Coastguard Worker #include <setjmp.h>
3*c9945492SAndroid Build Coastguard Worker #include <limits.h>
4*c9945492SAndroid Build Coastguard Worker #include "pthread_impl.h"
5*c9945492SAndroid Build Coastguard Worker #include "atomic.h"
6*c9945492SAndroid Build Coastguard Worker 
7*c9945492SAndroid Build Coastguard Worker struct ksigevent {
8*c9945492SAndroid Build Coastguard Worker 	union sigval sigev_value;
9*c9945492SAndroid Build Coastguard Worker 	int sigev_signo;
10*c9945492SAndroid Build Coastguard Worker 	int sigev_notify;
11*c9945492SAndroid Build Coastguard Worker 	int sigev_tid;
12*c9945492SAndroid Build Coastguard Worker };
13*c9945492SAndroid Build Coastguard Worker 
14*c9945492SAndroid Build Coastguard Worker struct start_args {
15*c9945492SAndroid Build Coastguard Worker 	pthread_barrier_t b;
16*c9945492SAndroid Build Coastguard Worker 	struct sigevent *sev;
17*c9945492SAndroid Build Coastguard Worker };
18*c9945492SAndroid Build Coastguard Worker 
dummy_0()19*c9945492SAndroid Build Coastguard Worker static void dummy_0()
20*c9945492SAndroid Build Coastguard Worker {
21*c9945492SAndroid Build Coastguard Worker }
22*c9945492SAndroid Build Coastguard Worker weak_alias(dummy_0, __pthread_tsd_run_dtors);
23*c9945492SAndroid Build Coastguard Worker 
cleanup_fromsig(void * p)24*c9945492SAndroid Build Coastguard Worker static void cleanup_fromsig(void *p)
25*c9945492SAndroid Build Coastguard Worker {
26*c9945492SAndroid Build Coastguard Worker 	pthread_t self = __pthread_self();
27*c9945492SAndroid Build Coastguard Worker 	__pthread_tsd_run_dtors();
28*c9945492SAndroid Build Coastguard Worker 	self->cancel = 0;
29*c9945492SAndroid Build Coastguard Worker 	self->cancelbuf = 0;
30*c9945492SAndroid Build Coastguard Worker 	self->canceldisable = 0;
31*c9945492SAndroid Build Coastguard Worker 	self->cancelasync = 0;
32*c9945492SAndroid Build Coastguard Worker 	__reset_tls();
33*c9945492SAndroid Build Coastguard Worker 	longjmp(p, 1);
34*c9945492SAndroid Build Coastguard Worker }
35*c9945492SAndroid Build Coastguard Worker 
start(void * arg)36*c9945492SAndroid Build Coastguard Worker static void *start(void *arg)
37*c9945492SAndroid Build Coastguard Worker {
38*c9945492SAndroid Build Coastguard Worker 	pthread_t self = __pthread_self();
39*c9945492SAndroid Build Coastguard Worker 	struct start_args *args = arg;
40*c9945492SAndroid Build Coastguard Worker 	jmp_buf jb;
41*c9945492SAndroid Build Coastguard Worker 
42*c9945492SAndroid Build Coastguard Worker 	void (*notify)(union sigval) = args->sev->sigev_notify_function;
43*c9945492SAndroid Build Coastguard Worker 	union sigval val = args->sev->sigev_value;
44*c9945492SAndroid Build Coastguard Worker 
45*c9945492SAndroid Build Coastguard Worker 	pthread_barrier_wait(&args->b);
46*c9945492SAndroid Build Coastguard Worker 	if (self->cancel)
47*c9945492SAndroid Build Coastguard Worker 		return 0;
48*c9945492SAndroid Build Coastguard Worker 	for (;;) {
49*c9945492SAndroid Build Coastguard Worker 		siginfo_t si;
50*c9945492SAndroid Build Coastguard Worker 		while (sigwaitinfo(SIGTIMER_SET, &si) < 0);
51*c9945492SAndroid Build Coastguard Worker 		if (si.si_code == SI_TIMER && !setjmp(jb)) {
52*c9945492SAndroid Build Coastguard Worker 			pthread_cleanup_push(cleanup_fromsig, jb);
53*c9945492SAndroid Build Coastguard Worker 			notify(val);
54*c9945492SAndroid Build Coastguard Worker 			pthread_cleanup_pop(1);
55*c9945492SAndroid Build Coastguard Worker 		}
56*c9945492SAndroid Build Coastguard Worker 		if (self->timer_id < 0) break;
57*c9945492SAndroid Build Coastguard Worker 	}
58*c9945492SAndroid Build Coastguard Worker 	__syscall(SYS_timer_delete, self->timer_id & INT_MAX);
59*c9945492SAndroid Build Coastguard Worker 	return 0;
60*c9945492SAndroid Build Coastguard Worker }
61*c9945492SAndroid Build Coastguard Worker 
timer_create(clockid_t clk,struct sigevent * restrict evp,timer_t * restrict res)62*c9945492SAndroid Build Coastguard Worker int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res)
63*c9945492SAndroid Build Coastguard Worker {
64*c9945492SAndroid Build Coastguard Worker 	static volatile int init = 0;
65*c9945492SAndroid Build Coastguard Worker 	pthread_t td;
66*c9945492SAndroid Build Coastguard Worker 	pthread_attr_t attr;
67*c9945492SAndroid Build Coastguard Worker 	int r;
68*c9945492SAndroid Build Coastguard Worker 	struct start_args args;
69*c9945492SAndroid Build Coastguard Worker 	struct ksigevent ksev, *ksevp=0;
70*c9945492SAndroid Build Coastguard Worker 	int timerid;
71*c9945492SAndroid Build Coastguard Worker 	sigset_t set;
72*c9945492SAndroid Build Coastguard Worker 
73*c9945492SAndroid Build Coastguard Worker 	switch (evp ? evp->sigev_notify : SIGEV_SIGNAL) {
74*c9945492SAndroid Build Coastguard Worker 	case SIGEV_NONE:
75*c9945492SAndroid Build Coastguard Worker 	case SIGEV_SIGNAL:
76*c9945492SAndroid Build Coastguard Worker 	case SIGEV_THREAD_ID:
77*c9945492SAndroid Build Coastguard Worker 		if (evp) {
78*c9945492SAndroid Build Coastguard Worker 			ksev.sigev_value = evp->sigev_value;
79*c9945492SAndroid Build Coastguard Worker 			ksev.sigev_signo = evp->sigev_signo;
80*c9945492SAndroid Build Coastguard Worker 			ksev.sigev_notify = evp->sigev_notify;
81*c9945492SAndroid Build Coastguard Worker 			if (evp->sigev_notify == SIGEV_THREAD_ID)
82*c9945492SAndroid Build Coastguard Worker 				ksev.sigev_tid = evp->sigev_notify_thread_id;
83*c9945492SAndroid Build Coastguard Worker 			else
84*c9945492SAndroid Build Coastguard Worker 				ksev.sigev_tid = 0;
85*c9945492SAndroid Build Coastguard Worker 			ksevp = &ksev;
86*c9945492SAndroid Build Coastguard Worker 		}
87*c9945492SAndroid Build Coastguard Worker 		if (syscall(SYS_timer_create, clk, ksevp, &timerid) < 0)
88*c9945492SAndroid Build Coastguard Worker 			return -1;
89*c9945492SAndroid Build Coastguard Worker 		*res = (void *)(intptr_t)timerid;
90*c9945492SAndroid Build Coastguard Worker 		break;
91*c9945492SAndroid Build Coastguard Worker 	case SIGEV_THREAD:
92*c9945492SAndroid Build Coastguard Worker 		if (!init) {
93*c9945492SAndroid Build Coastguard Worker 			struct sigaction sa = { .sa_handler = SIG_DFL };
94*c9945492SAndroid Build Coastguard Worker 			__libc_sigaction(SIGTIMER, &sa, 0);
95*c9945492SAndroid Build Coastguard Worker 			a_store(&init, 1);
96*c9945492SAndroid Build Coastguard Worker 		}
97*c9945492SAndroid Build Coastguard Worker 		if (evp->sigev_notify_attributes)
98*c9945492SAndroid Build Coastguard Worker 			attr = *evp->sigev_notify_attributes;
99*c9945492SAndroid Build Coastguard Worker 		else
100*c9945492SAndroid Build Coastguard Worker 			pthread_attr_init(&attr);
101*c9945492SAndroid Build Coastguard Worker 		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
102*c9945492SAndroid Build Coastguard Worker 		pthread_barrier_init(&args.b, 0, 2);
103*c9945492SAndroid Build Coastguard Worker 		args.sev = evp;
104*c9945492SAndroid Build Coastguard Worker 
105*c9945492SAndroid Build Coastguard Worker 		__block_app_sigs(&set);
106*c9945492SAndroid Build Coastguard Worker 		__syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGTIMER_SET, 0, _NSIG/8);
107*c9945492SAndroid Build Coastguard Worker 		r = pthread_create(&td, &attr, start, &args);
108*c9945492SAndroid Build Coastguard Worker 		__restore_sigs(&set);
109*c9945492SAndroid Build Coastguard Worker 		if (r) {
110*c9945492SAndroid Build Coastguard Worker 			errno = r;
111*c9945492SAndroid Build Coastguard Worker 			return -1;
112*c9945492SAndroid Build Coastguard Worker 		}
113*c9945492SAndroid Build Coastguard Worker 
114*c9945492SAndroid Build Coastguard Worker 		ksev.sigev_value.sival_ptr = 0;
115*c9945492SAndroid Build Coastguard Worker 		ksev.sigev_signo = SIGTIMER;
116*c9945492SAndroid Build Coastguard Worker 		ksev.sigev_notify = SIGEV_THREAD_ID;
117*c9945492SAndroid Build Coastguard Worker 		ksev.sigev_tid = td->tid;
118*c9945492SAndroid Build Coastguard Worker 		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) {
119*c9945492SAndroid Build Coastguard Worker 			timerid = -1;
120*c9945492SAndroid Build Coastguard Worker 			td->cancel = 1;
121*c9945492SAndroid Build Coastguard Worker 		}
122*c9945492SAndroid Build Coastguard Worker 		td->timer_id = timerid;
123*c9945492SAndroid Build Coastguard Worker 		pthread_barrier_wait(&args.b);
124*c9945492SAndroid Build Coastguard Worker 		if (timerid < 0) return -1;
125*c9945492SAndroid Build Coastguard Worker 		*res = (void *)(INTPTR_MIN | (uintptr_t)td>>1);
126*c9945492SAndroid Build Coastguard Worker 		break;
127*c9945492SAndroid Build Coastguard Worker 	default:
128*c9945492SAndroid Build Coastguard Worker 		errno = EINVAL;
129*c9945492SAndroid Build Coastguard Worker 		return -1;
130*c9945492SAndroid Build Coastguard Worker 	}
131*c9945492SAndroid Build Coastguard Worker 
132*c9945492SAndroid Build Coastguard Worker 	return 0;
133*c9945492SAndroid Build Coastguard Worker }
134