fix incorrect (and conflicting on LP64 archs) types for sysv ipc msgq functions
[musl] / src / time / timer_create.c
index 1ac1906..e35293c 100644 (file)
@@ -11,41 +11,42 @@ struct ksigevent {
 struct start_args {
        pthread_barrier_t b;
        struct sigevent *sev;
-       timer_t t;
 };
 
-static void sighandler(int sig, siginfo_t *si, void *ctx)
+void __sigtimer_handler(pthread_t self)
 {
        int st;
-       timer_t t = si->si_value.sival_ptr;
+       void (*notify)(union sigval) = (void (*)(union sigval))self->start;
+       union sigval val = { .sival_ptr = self->start_arg };
+
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &st);
-       t->notify(t->val);
+       notify(val);
        pthread_setcancelstate(st, 0);
 }
 
-static void killtimer(void *arg)
+static void cleanup(void *p)
 {
-       timer_t t = arg;
-       if (t->timerid >= 0) __syscall(SYS_timer_delete, t->timerid);
+       pthread_t self = p;
+       __syscall(SYS_timer_delete, self->result);
 }
 
 static void *start(void *arg)
 {
+       pthread_t self = __pthread_self();
        struct start_args *args = arg;
-       struct __timer t = {
-               .notify = args->sev->sigev_notify_function,
-               .val = args->sev->sigev_value,
-       };
 
-       args->t = &t;
+       /* Reuse no-longer-needed thread structure fields to avoid
+        * needing the timer address in the signal handler. */
+       self->start = (void *(*)(void *))args->sev->sigev_notify_function;
+       self->start_arg = args->sev->sigev_value.sival_ptr;
+       self->result = (void *)-1;
 
+       pthread_cleanup_push(cleanup, self);
        pthread_barrier_wait(&args->b);
-
-       pthread_cleanup_push(killtimer, &t);
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
        /* Loop on async-signal-safe cancellation point */
-       for (;;) sleep(1);
-       pthread_cleanup_pop(1);
+       for (;;) sleep(1000000000);
+       pthread_cleanup_pop(0);
        return 0;
 }
 
@@ -61,19 +62,21 @@ int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
        struct start_args args;
        timer_t t;
        struct ksigevent ksev;
+       int timerid;
 
        if (evp) sev = *evp;
 
        switch (sev.sigev_notify) {
        case SIGEV_NONE:
        case SIGEV_SIGNAL:
-               if (!(t = calloc(1, sizeof *t)))
-                       return -1;
                ksev.sigev_value = evp ? sev.sigev_value
                        : (union sigval){.sival_ptr=t};
                ksev.sigev_signo = sev.sigev_signo;
                ksev.sigev_notify = sev.sigev_notify;
                ksev.sigev_tid = 0;
+               if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0)
+                       return -1;
+               *res = (void *)(2*timerid+1);
                break;
        case SIGEV_THREAD:
                if (sev.sigev_notify_attributes)
@@ -88,23 +91,23 @@ int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
                        errno = r;
                        return -1;
                }
-               pthread_barrier_wait(&args.b);
-               t = args.t;
-               t->thread = td;
-               ksev.sigev_value.sival_ptr = t;
+               ksev.sigev_value.sival_ptr = 0;
                ksev.sigev_signo = SIGCANCEL;
                ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */
                ksev.sigev_tid = td->tid;
-               if (!libc.sigtimer) libc.sigtimer = sighandler;
+               r = syscall(SYS_timer_create, clk, &ksev, &timerid);
+               pthread_barrier_wait(&args.b);
+               if (r < 0) {
+                       pthread_cancel(td);
+                       return -1;
+               }
+               td->result = (void *)timerid;
+               *res = td;
                break;
-       }
-
-       t->timerid = -1;
-       if (syscall(SYS_timer_create, clk, &ksev, &t->timerid) < 0) {
-               timer_delete(t);
+       default:
+               errno = EINVAL;
                return -1;
        }
 
-       *res = t;
        return 0;
 }