optimize cancellation enable/disable code
authorRich Felker <dalias@aerifal.cx>
Sun, 17 Apr 2011 17:21:13 +0000 (13:21 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 17 Apr 2011 17:21:13 +0000 (13:21 -0400)
the goal is to be able to use pthread_setcancelstate internally in
the implementation, whenever a function might want to use functions
which are cancellation points but avoid becoming a cancellation point
itself. i could have just used a separate internal function for
temporarily inhibiting cancellation, but the solution in this commit
is better because (1) it's one less implementation-specific detail in
functions that need to use it, and (2) application code can also get
the same benefit.

previously, pthread_setcancelstate dependend on pthread_self, which
would pull in unwanted thread setup overhead for non-threaded
programs. now, it temporarily stores the state in the global libc
struct if threads have not been initialized, and later moves it if
needed. this way we can instead use __pthread_self, which has no
dependencies and assumes that the thread register is already valid.

src/internal/libc.h
src/thread/pthread_self.c
src/thread/pthread_setcancelstate.c
src/thread/pthread_setcanceltype.c

index 3f1e55e53ac5e4556c2becced197b75e8203f55b..d6df93d0a40cf9a79fe35c0a11f1db97ece05fb3 100644 (file)
@@ -16,6 +16,7 @@ struct __libc {
        volatile int threads_minus_1;
        int ofl_lock;
        FILE *ofl_head;
+       int canceldisable;
 };
 
 
index 83efa9e874da9119c82d6c8e86c9848bf23f8e04..e26476cedffd37ae171e9945f856607a239cda71 100644 (file)
@@ -14,6 +14,7 @@ static int *errno_location()
 
 static int init_main_thread()
 {
+       main_thread.canceldisable = libc.canceldisable;
        main_thread.tsd = (void **)__pthread_tsd_main;
        main_thread.self = &main_thread;
        if (__set_thread_area(&main_thread) < 0)
index aa0ddcdd316341ec0ab7a685e2e84a5a8a2b149b..6722541a27e73e190b00973997432c5d4fcc375c 100644 (file)
@@ -2,9 +2,14 @@
 
 int pthread_setcancelstate(int new, int *old)
 {
-       struct pthread *self = pthread_self();
-       if (old) *old = self->canceldisable;
        if (new > 1U) return EINVAL;
-       self->canceldisable = new;
+       if (libc.lock) {
+               struct pthread *self = __pthread_self();
+               if (old) *old = self->canceldisable;
+               self->canceldisable = new;
+       } else {
+               if (old) *old = libc.canceldisable;
+               libc.canceldisable = new;
+       }
        return 0;
 }
index c73db22f3b614cf486725876ee9a2ee61c084590..7eb543a8961e63a0eddff2b128d0229b179d3dfa 100644 (file)
@@ -3,8 +3,8 @@
 int pthread_setcanceltype(int new, int *old)
 {
        struct pthread *self = pthread_self();
+       if (new > 1U) return EINVAL;
        if (old) *old = self->cancelasync;
-       if ((unsigned)new > 1) return EINVAL;
        self->cancelasync = new;
        return 0;
 }