OLD | NEW |
1 #include <time.h> | 1 #include <time.h> |
2 #include <setjmp.h> | 2 #include <setjmp.h> |
3 #include "pthread_impl.h" | 3 #include "pthread_impl.h" |
4 | 4 |
5 struct ksigevent { | 5 struct ksigevent { |
6 » union sigval sigev_value; | 6 union sigval sigev_value; |
7 » int sigev_signo; | 7 int sigev_signo; |
8 » int sigev_notify; | 8 int sigev_notify; |
9 » int sigev_tid; | 9 int sigev_tid; |
10 }; | 10 }; |
11 | 11 |
12 struct start_args { | 12 struct start_args { |
13 » pthread_barrier_t b; | 13 pthread_barrier_t b; |
14 » struct sigevent *sev; | 14 struct sigevent* sev; |
15 }; | 15 }; |
16 | 16 |
17 static void dummy_1(pthread_t self) | 17 static void dummy_1(pthread_t self) {} |
18 { | |
19 } | |
20 weak_alias(dummy_1, __pthread_tsd_run_dtors); | 18 weak_alias(dummy_1, __pthread_tsd_run_dtors); |
21 | 19 |
22 void __reset_tls(); | 20 void __reset_tls(); |
23 | 21 |
24 static void cleanup_fromsig(void *p) | 22 static void cleanup_fromsig(void* p) { |
25 { | 23 pthread_t self = __pthread_self(); |
26 » pthread_t self = __pthread_self(); | 24 __pthread_tsd_run_dtors(self); |
27 » __pthread_tsd_run_dtors(self); | 25 self->cancel = 0; |
28 » self->cancel = 0; | 26 self->cancelbuf = 0; |
29 » self->cancelbuf = 0; | 27 self->canceldisable = 0; |
30 » self->canceldisable = 0; | 28 self->cancelasync = 0; |
31 » self->cancelasync = 0; | 29 self->unblock_cancel = 0; |
32 » self->unblock_cancel = 0; | 30 __reset_tls(); |
33 » __reset_tls(); | 31 longjmp(p, 1); |
34 » longjmp(p, 1); | |
35 } | 32 } |
36 | 33 |
37 static void timer_handler(int sig, siginfo_t *si, void *ctx) | 34 static void timer_handler(int sig, siginfo_t* si, void* ctx) { |
38 { | 35 pthread_t self = __pthread_self(); |
39 » pthread_t self = __pthread_self(); | 36 jmp_buf jb; |
40 » jmp_buf jb; | 37 void (*notify)(union sigval) = (void (*)(union sigval))self->start; |
41 » void (*notify)(union sigval) = (void (*)(union sigval))self->start; | 38 union sigval val = {.sival_ptr = self->start_arg}; |
42 » union sigval val = { .sival_ptr = self->start_arg }; | |
43 | 39 |
44 » if (!setjmp(jb) && si->si_code == SI_TIMER) { | 40 if (!setjmp(jb) && si->si_code == SI_TIMER) { |
45 » » pthread_cleanup_push(cleanup_fromsig, jb); | 41 pthread_cleanup_push(cleanup_fromsig, jb); |
46 » » notify(val); | 42 notify(val); |
47 » » pthread_cleanup_pop(1); | 43 pthread_cleanup_pop(1); |
48 » } | 44 } |
49 } | 45 } |
50 | 46 |
51 static void install_handler() | 47 static void install_handler() { |
52 { | 48 struct sigaction sa = {.sa_sigaction = timer_handler, |
53 » struct sigaction sa = { | 49 .sa_flags = SA_SIGINFO | SA_RESTART}; |
54 » » .sa_sigaction = timer_handler, | 50 __libc_sigaction(SIGTIMER, &sa, 0); |
55 » » .sa_flags = SA_SIGINFO | SA_RESTART | |
56 » }; | |
57 » __libc_sigaction(SIGTIMER, &sa, 0); | |
58 } | 51 } |
59 | 52 |
60 static void *start(void *arg) | 53 static void* start(void* arg) { |
61 { | 54 pthread_t self = __pthread_self(); |
62 » pthread_t self = __pthread_self(); | 55 struct start_args* args = arg; |
63 » struct start_args *args = arg; | 56 int id; |
64 » int id; | |
65 | 57 |
66 » /* Reuse no-longer-needed thread structure fields to avoid | 58 /* Reuse no-longer-needed thread structure fields to avoid |
67 » * needing the timer address in the signal handler. */ | 59 * needing the timer address in the signal handler. */ |
68 » self->start = (void *(*)(void *))args->sev->sigev_notify_function; | 60 self->start = (void* (*)(void*))args->sev->sigev_notify_function; |
69 » self->start_arg = args->sev->sigev_value.sival_ptr; | 61 self->start_arg = args->sev->sigev_value.sival_ptr; |
70 | 62 |
71 » pthread_barrier_wait(&args->b); | 63 pthread_barrier_wait(&args->b); |
72 » if ((id = self->timer_id) >= 0) { | 64 if ((id = self->timer_id) >= 0) { |
73 » » __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, | 65 __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGTIMER_SET, 0, _NSIG / 8); |
74 » » » SIGTIMER_SET, 0, _NSIG/8); | 66 __wait(&self->timer_id, 0, id, 1); |
75 » » __wait(&self->timer_id, 0, id, 1); | 67 __syscall(SYS_timer_delete, id); |
76 » » __syscall(SYS_timer_delete, id); | 68 } |
77 » } | 69 return 0; |
78 » return 0; | |
79 } | 70 } |
80 | 71 |
81 int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
res) | 72 int timer_create(clockid_t clk, |
82 { | 73 struct sigevent* restrict evp, |
83 » static pthread_once_t once = PTHREAD_ONCE_INIT; | 74 timer_t* restrict res) { |
84 » pthread_t td; | 75 static pthread_once_t once = PTHREAD_ONCE_INIT; |
85 » pthread_attr_t attr; | 76 pthread_t td; |
86 » int r; | 77 pthread_attr_t attr; |
87 » struct start_args args; | 78 int r; |
88 » struct ksigevent ksev, *ksevp=0; | 79 struct start_args args; |
89 » int timerid; | 80 struct ksigevent ksev, *ksevp = 0; |
90 » sigset_t set; | 81 int timerid; |
| 82 sigset_t set; |
91 | 83 |
92 » switch (evp ? evp->sigev_notify : SIGEV_SIGNAL) { | 84 switch (evp ? evp->sigev_notify : SIGEV_SIGNAL) { |
93 » case SIGEV_NONE: | 85 case SIGEV_NONE: |
94 » case SIGEV_SIGNAL: | 86 case SIGEV_SIGNAL: |
95 » » if (evp) { | 87 if (evp) { |
96 » » » ksev.sigev_value = evp->sigev_value; | 88 ksev.sigev_value = evp->sigev_value; |
97 » » » ksev.sigev_signo = evp->sigev_signo; | 89 ksev.sigev_signo = evp->sigev_signo; |
98 » » » ksev.sigev_notify = evp->sigev_notify; | 90 ksev.sigev_notify = evp->sigev_notify; |
99 » » » ksev.sigev_tid = 0; | 91 ksev.sigev_tid = 0; |
100 » » » ksevp = &ksev; | 92 ksevp = &ksev; |
101 » » } | 93 } |
102 » » if (syscall(SYS_timer_create, clk, ksevp, &timerid) < 0) | 94 if (syscall(SYS_timer_create, clk, ksevp, &timerid) < 0) |
103 » » » return -1; | 95 return -1; |
104 » » *res = (void *)(intptr_t)timerid; | 96 *res = (void*)(intptr_t)timerid; |
105 » » break; | 97 break; |
106 » case SIGEV_THREAD: | 98 case SIGEV_THREAD: |
107 » » pthread_once(&once, install_handler); | 99 pthread_once(&once, install_handler); |
108 » » if (evp->sigev_notify_attributes) | 100 if (evp->sigev_notify_attributes) |
109 » » » attr = *evp->sigev_notify_attributes; | 101 attr = *evp->sigev_notify_attributes; |
110 » » else | 102 else |
111 » » » pthread_attr_init(&attr); | 103 pthread_attr_init(&attr); |
112 » » pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | 104 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
113 » » pthread_barrier_init(&args.b, 0, 2); | 105 pthread_barrier_init(&args.b, 0, 2); |
114 » » args.sev = evp; | 106 args.sev = evp; |
115 | 107 |
116 » » __block_app_sigs(&set); | 108 __block_app_sigs(&set); |
117 » » r = pthread_create(&td, &attr, start, &args); | 109 r = pthread_create(&td, &attr, start, &args); |
118 » » __restore_sigs(&set); | 110 __restore_sigs(&set); |
119 » » if (r) { | 111 if (r) { |
120 » » » errno = r; | 112 errno = r; |
121 » » » return -1; | 113 return -1; |
122 » » } | 114 } |
123 | 115 |
124 » » ksev.sigev_value.sival_ptr = 0; | 116 ksev.sigev_value.sival_ptr = 0; |
125 » » ksev.sigev_signo = SIGTIMER; | 117 ksev.sigev_signo = SIGTIMER; |
126 » » ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */ | 118 ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */ |
127 » » ksev.sigev_tid = td->tid; | 119 ksev.sigev_tid = td->tid; |
128 » » if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) | 120 if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) |
129 » » » timerid = -1; | 121 timerid = -1; |
130 » » td->timer_id = timerid; | 122 td->timer_id = timerid; |
131 » » pthread_barrier_wait(&args.b); | 123 pthread_barrier_wait(&args.b); |
132 » » if (timerid < 0) return -1; | 124 if (timerid < 0) |
133 » » *res = (void *)(INTPTR_MIN | (uintptr_t)td>>1); | 125 return -1; |
134 » » break; | 126 *res = (void*)(INTPTR_MIN | (uintptr_t)td >> 1); |
135 » default: | 127 break; |
136 » » errno = EINVAL; | 128 default: |
137 » » return -1; | 129 errno = EINVAL; |
138 » } | 130 return -1; |
| 131 } |
139 | 132 |
140 » return 0; | 133 return 0; |
141 } | 134 } |
OLD | NEW |