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