use a separate signal from SIGCANCEL for SIGEV_THREAD timers
authorRich Felker <dalias@aerifal.cx>
Thu, 14 Apr 2011 16:51:00 +0000 (12:51 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 14 Apr 2011 16:51:00 +0000 (12:51 -0400)
otherwise we cannot support an application's desire to use
asynchronous cancellation within the callback function. this change
also slightly debloats pthread_create.c.

src/internal/pthread_impl.h
src/signal/sigaction.c
src/signal/sigprocmask.c
src/signal/sigrtmin.c
src/thread/pthread_create.c
src/time/timer_create.c

index 3e436aefc94e02ba2c35fb716dccf3629ebb6497..a6d90e9bc184e92555fe507d9520c28cd86e1d4a 100644 (file)
@@ -76,6 +76,7 @@ struct __timer {
 
 #define SIGCANCEL 32
 #define SIGSYSCALL 33
+#define SIGTIMER 34
 
 int __set_thread_area(void *);
 int __libc_sigaction(int, const struct sigaction *, struct sigaction *);
index 3d374e1f45bf661a7a278fc1ba060ada8e3e6735..887bbc4f70989e4f837e12bcc5d6326221747016 100644 (file)
@@ -35,7 +35,7 @@ int __libc_sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
 
 int __sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
 {
-       if (sig == SIGCANCEL || sig == SIGSYSCALL) {
+       if (sig-SIGCANCEL < 3U) {
                errno = EINVAL;
                return -1;
        }
index 66b17a4228d9c57496dce365cd660ff950426958..a272c10d301df8fef5b9ea58f7b1a41d96a7130c 100644 (file)
@@ -22,6 +22,7 @@ int __sigprocmask(int how, const sigset_t *set, sigset_t *old)
                set = &tmp;
                sigdelset(&tmp, SIGCANCEL);
                sigdelset(&tmp, SIGSYSCALL);
+               sigdelset(&tmp, SIGTIMER);
        }
        return __libc_sigprocmask(how, set, old);
 }
index 7ad06d2258c4120a8f0198229700ef13a28925da..d0e769bbc15480a6e50cfa8f945d031eca284575 100644 (file)
@@ -1,4 +1,4 @@
 int __libc_current_sigrtmin()
 {
-       return 34;
+       return 35;
 }
index a782650420248683f9c94fc515edfd8e04a7e95a..a722a2d6fdbeb0a0e8c9f6e253cd10610c1987b9 100644 (file)
@@ -10,7 +10,6 @@ static void dummy_1(pthread_t self)
 {
 }
 weak_alias(dummy_1, __pthread_tsd_run_dtors);
-weak_alias(dummy_1, __sigtimer_handler);
 
 #ifdef __pthread_unwind_next
 #undef __pthread_unwind_next
@@ -54,7 +53,6 @@ static void docancel(struct pthread *self)
 static void cancel_handler(int sig, siginfo_t *si, void *ctx)
 {
        struct pthread *self = __pthread_self();
-       if (si->si_code == SI_TIMER) __sigtimer_handler(self);
        if (self->cancel && !self->canceldisable &&
            (self->cancelasync || (self->cancelpoint==1 && PC_AT_SYS(ctx))))
                docancel(self);
index c107e150d12a66794cb274b3b4066af9e2b6fe0b..cc10bef08b7b0bebc5977dcd360a20dacb052ddc 100644 (file)
@@ -21,22 +21,38 @@ weak_alias(dummy_1, __pthread_tsd_run_dtors);
 static void cleanup_fromsig(void *p)
 {
        pthread_t self = __pthread_self();
+       __pthread_tsd_run_dtors(self);
        self->cancel = 0;
        self->cancelbuf = 0;
-       __pthread_tsd_run_dtors(self);
+       self->canceldisable = 0;
+       self->cancelasync = 0;
+       self->unblock_cancel = 0;
        longjmp(p, 1);
 }
 
-void __sigtimer_handler(pthread_t self)
+static void timer_handler(int sig, siginfo_t *si, void *ctx)
 {
+       pthread_t self = __pthread_self();
        jmp_buf jb;
        void (*notify)(union sigval) = (void (*)(union sigval))self->start;
        union sigval val = { .sival_ptr = self->start_arg };
 
-       if (setjmp(jb)) return;
-       pthread_cleanup_push(cleanup_fromsig, jb);
-       notify(val);
-       pthread_cleanup_pop(0);
+       if (!setjmp(jb) && si->si_code == SI_TIMER) {
+               pthread_cleanup_push(cleanup_fromsig, jb);
+               notify(val);
+               pthread_cleanup_pop(0);
+       }
+}
+
+static void install_handler()
+{
+       struct sigaction sa = {
+               .sa_sigaction = timer_handler,
+               .sa_flags = SA_SIGINFO | SA_RESTART
+       };
+       __libc_sigaction(SIGTIMER, &sa, 0);
+       sigaddset(&sa.sa_mask, SIGTIMER);
+       __libc_sigprocmask(SIG_UNBLOCK, &sa.sa_mask, 0);
 }
 
 static void *start(void *arg)
@@ -58,6 +74,7 @@ static void *start(void *arg)
 
 int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
 {
+       static pthread_once_t once = PTHREAD_ONCE_INIT;
        pthread_t td;
        pthread_attr_t attr;
        int r;
@@ -80,6 +97,7 @@ int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
                *res = (void *)timerid;
                break;
        case SIGEV_THREAD:
+               pthread_once(&once, install_handler);
                if (evp->sigev_notify_attributes)
                        attr = *evp->sigev_notify_attributes;
                else
@@ -93,7 +111,7 @@ int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res)
                        return -1;
                }
                ksev.sigev_value.sival_ptr = 0;
-               ksev.sigev_signo = SIGCANCEL;
+               ksev.sigev_signo = SIGTIMER;
                ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */
                ksev.sigev_tid = td->tid;
                r = syscall(SYS_timer_create, clk, &ksev, &timerid);