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