| File: | src/time/timer_create.c |
| Location: | line 104, column 8 |
| Description: | Assigned value is garbage or undefined |
| 1 | #include <time.h> | |||
| 2 | #include <setjmpsetjmp.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)extern __typeof(dummy_1) __pthread_tsd_run_dtors __attribute__ ((weak, alias("dummy_1"))); | |||
| 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 (!setjmpsetjmp(jb) && si->si_code == SI_TIMER(-2)) { | |||
| 45 | pthread_cleanup_push(cleanup_fromsig, jb)do { struct __ptcb __cb; _pthread_cleanup_push(&__cb, cleanup_fromsig , jb);; | |||
| 46 | notify(val); | |||
| 47 | pthread_cleanup_pop(1)_pthread_cleanup_pop(&__cb, (1)); } while(0); | |||
| 48 | } | |||
| 49 | } | |||
| 50 | ||||
| 51 | static void install_handler() | |||
| 52 | { | |||
| 53 | struct sigaction sa = { | |||
| 54 | .sa_sigaction__sa_handler.sa_sigaction = timer_handler, | |||
| 55 | .sa_flags = SA_SIGINFO4 | SA_RESTART0x10000000 | |||
| 56 | }; | |||
| 57 | __libc_sigaction(SIGTIMER32, &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,__syscall4(175,((long) (1)),((long) (((sigset_t *)(const unsigned long [65/8/sizeof(long)]){ 0x80000000 }))),((long) (0)),((long ) (65/8))) | |||
| 74 | SIGTIMER_SET, 0, _NSIG/8)__syscall4(175,((long) (1)),((long) (((sigset_t *)(const unsigned long [65/8/sizeof(long)]){ 0x80000000 }))),((long) (0)),((long ) (65/8))); | |||
| 75 | __wait(&self->timer_id, 0, id, 1); | |||
| 76 | __syscall(SYS_timer_delete, id)__syscall1(261,((long) (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_INIT0; | |||
| 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_SIGNAL0) { | |||
| 93 | case SIGEV_NONE1: | |||
| 94 | case SIGEV_SIGNAL0: | |||
| 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)__syscall_ret(__syscall3(257,((long) (clk)),((long) (ksevp)), ((long) (&timerid)))) < 0) | |||
| 103 | return -1; | |||
| 104 | *res = (void *)(intptr_t)timerid; | |||
| ||||
| 105 | break; | |||
| 106 | case SIGEV_THREAD2: | |||
| 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_DETACHED1); | |||
| 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(*__errno_location()) = r; | |||
| 121 | return -1; | |||
| 122 | } | |||
| 123 | ||||
| 124 | ksev.sigev_value.sival_ptr = 0; | |||
| 125 | ksev.sigev_signo = SIGTIMER32; | |||
| 126 | ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */ | |||
| 127 | ksev.sigev_tid = td->tid; | |||
| 128 | if (syscall(SYS_timer_create, clk, &ksev, &timerid)__syscall_ret(__syscall3(257,((long) (clk)),((long) (&ksev )),((long) (&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(-1-0x7fffffff) | (uintptr_t)td>>1); | |||
| 134 | break; | |||
| 135 | default: | |||
| 136 | errno(*__errno_location()) = EINVAL22; | |||
| 137 | return -1; | |||
| 138 | } | |||
| 139 | ||||
| 140 | return 0; | |||
| 141 | } |