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