avoid all malloc/free in timer creation/destruction
authorRich Felker <dalias@aerifal.cx>
Wed, 30 Mar 2011 17:04:55 +0000 (13:04 -0400)
committerRich Felker <dalias@aerifal.cx>
Wed, 30 Mar 2011 17:04:55 +0000 (13:04 -0400)
instead of allocating a userspace structure for signal-based timers,
simply use the kernel timer id. we use the fact that thread pointers
will always be zero in the low bit (actually more) to encode integer
timerid values as pointers.

also, this change ensures that the timer_destroy syscall has completed
before the library timer_destroy function returns, in case it matters.

arch/i386/bits/alltypes.h.sh
arch/x86_64/bits/alltypes.h.sh
src/time/timer_create.c
src/time/timer_delete.c
src/time/timer_getoverrun.c
src/time/timer_gettime.c
src/time/timer_settime.c

index 13658cc2716ae001ec204f204a0b9a2f5e490e22..c6201b9dc2e9fae35c13fa00516ac815c0be0867 100755 (executable)
@@ -107,7 +107,7 @@ TYPEDEF long long blkcnt_t;
 TYPEDEF unsigned long long fsblkcnt_t;
 TYPEDEF unsigned long long fsfilcnt_t;
 
-TYPEDEF struct __timer * timer_t;
+TYPEDEF void * timer_t;
 TYPEDEF int clockid_t;
 TYPEDEF unsigned long clock_t;
 
index cd84a2dad79dae90876dcf88fa32fac322fdcac9..b0aecd9c94c875c5eef4ae8a3395f2fc3624ee5a 100755 (executable)
@@ -107,7 +107,7 @@ TYPEDEF long long blkcnt_t;
 TYPEDEF unsigned long long fsblkcnt_t;
 TYPEDEF unsigned long long fsfilcnt_t;
 
-TYPEDEF struct __timer * timer_t;
+TYPEDEF void * timer_t;
 TYPEDEF int clockid_t;
 TYPEDEF long clock_t;
 
index 89099dd6b8961ed816d1fd0bc998006431374fb6..c5894f48060f195e5d16e99a4636f1cd28565ab0 100644 (file)
@@ -11,7 +11,6 @@ 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)
@@ -26,30 +25,21 @@ static void sighandler(int sig, siginfo_t *si, void *ctx)
        pthread_setcancelstate(st, 0);
 }
 
-static void killtimer(void *arg)
-{
-       timer_t t = arg;
-       if (t->timerid >= 0) __syscall(SYS_timer_delete, t->timerid);
-}
-
 static void *start(void *arg)
 {
        pthread_t self = __pthread_self();
        struct start_args *args = arg;
-       struct __timer t = { .timerid = -1 };
 
        /* 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;
-       args->t = &t;
+       self->result = (void *)-1;
 
-       pthread_cleanup_push(killtimer, &t);
        pthread_barrier_wait(&args->b);
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
        /* Loop on async-signal-safe cancellation point */
        for (;;) sleep(1);
-       pthread_cleanup_pop(1);
        return 0;
 }
 
@@ -79,11 +69,7 @@ int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
                ksev.sigev_tid = 0;
                if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0)
                        return -1;
-               if (!(t = calloc(1, sizeof *t))) {
-                       syscall(SYS_timer_delete, timerid);
-                       return -1;
-               }
-               t->timerid = timerid;
+               *res = (void *)(2*timerid+1);
                break;
        case SIGEV_THREAD:
                if (!libc.sigtimer) libc.sigtimer = sighandler;
@@ -105,19 +91,17 @@ int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
                ksev.sigev_tid = td->tid;
                r = syscall(SYS_timer_create, clk, &ksev, &timerid);
                pthread_barrier_wait(&args.b);
-               t = args.t;
                if (r < 0) {
                        pthread_cancel(td);
                        return -1;
                }
-               t->timerid = timerid;
-               t->thread = td;
+               td->result = (void *)timerid;
+               *res = td;
                break;
        default:
                errno = EINVAL;
                return -1;
        }
 
-       *res = t;
        return 0;
 }
index caf048954c040c36e7d98806400b687f56da0710..437de2e06a32926cdb71ef3709f420f23eb83146 100644 (file)
@@ -3,10 +3,11 @@
 
 int timer_delete(timer_t t)
 {
-       if (t->thread) pthread_cancel(t->thread);
-       else {
-               __syscall(SYS_timer_delete, t->timerid);
-               free(t);
-       }
-       return 0;
+       pthread_t td = 0;
+       int r;
+       if ((uintptr_t)t & 1) t = (void *)((unsigned long)t / 2);
+       else td = t, t = td->result;
+       r = __syscall(SYS_timer_delete, (long)t);
+       if (td) pthread_cancel(td);
+       return r;
 }
index 1334e451cb1a259f22249adf0da147dea63dc1c9..fa7715bbe73f47e03a3a28d5a66210f771eb6e74 100644 (file)
@@ -3,5 +3,7 @@
 
 int timer_getoverrun(timer_t t)
 {
-       return syscall(SYS_timer_getoverrun, t->timerid);
+       if ((uintptr_t)t & 1) t = (void *)((unsigned long)t / 2);
+       else t = ((pthread_t)t)->result;
+       return syscall(SYS_timer_getoverrun, (long)t);
 }
index 3d3156a060290cf3b743eda1cb9526e9fe7dba72..2320873eecf22c06f8cc30735e7b2df82e74239a 100644 (file)
@@ -3,5 +3,7 @@
 
 int timer_gettime(timer_t t, struct itimerspec *val)
 {
-       return syscall(SYS_timer_gettime, t->timerid, val);
+       if ((uintptr_t)t & 1) t = (void *)((unsigned long)t / 2);
+       else t = ((pthread_t)t)->result;
+       return syscall(SYS_timer_gettime, (long)t, val);
 }
index d109570b3fe660cf193b8b6ae4e180714f391164..00708f0e47a6d90a1c50094beeb0c1f965b407ad 100644 (file)
@@ -3,5 +3,7 @@
 
 int timer_settime(timer_t t, int flags, const struct itimerspec *val, struct itimerspec *old)
 {
-       return syscall(SYS_timer_settime, t->timerid, flags, val, old);
+       if ((uintptr_t)t & 1) t = (void *)((unsigned long)t / 2);
+       else t = ((pthread_t)t)->result;
+       return syscall(SYS_timer_settime, (long)t, flags, val, old);
 }