new framework to inhibit thread cancellation when needed
authorRich Felker <dalias@aerifal.cx>
Tue, 5 Apr 2011 22:00:28 +0000 (18:00 -0400)
committerRich Felker <dalias@aerifal.cx>
Tue, 5 Apr 2011 22:00:28 +0000 (18:00 -0400)
with these small changes, libc functions which need to call functions
which are cancellation points, but which themselves must not be
cancellation points, can use the CANCELPT_INHIBIT and CANCELPT_RESUME
macros to temporarily inhibit all cancellation.

src/internal/libc.h
src/thread/pthread_create.c
src/thread/pthread_setcancelstate.c

index b80cbcc9ef61e033e41cd796abace1f465642e75..be88dc04c28cafd6a02c3ed73f6a70b4a8fb67a2 100644 (file)
@@ -45,6 +45,8 @@ void __lockfile(FILE *);
 #define CANCELPT_BEGIN CANCELPT(1)
 #define CANCELPT_TRY CANCELPT(0)
 #define CANCELPT_END CANCELPT(-1)
+#define CANCELPT_INHIBIT CANCELPT(2)
+#define CANCELPT_RESUME CANCELPT(-2)
 
 extern char **__environ;
 #define environ __environ
index 284b45a0f39c5639e8d7d4c0a1460d235c9e1983..52487001484ce8c1edfc08cd7b7027055c4a130d 100644 (file)
@@ -57,9 +57,19 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)
 static void cancelpt(int x)
 {
        struct pthread *self = __pthread_self();
-       if (self->canceldisable) return;
-       if ((self->cancelpoint+=x)==1 && x>=0 && self->cancel)
-               docancel(self);
+       switch (x) {
+       case 1:
+               self->cancelpoint++;
+       case 0:
+               if (self->cancel && self->cancelpoint==1 && !self->canceldisable)
+                       docancel(self);
+               break;
+       case -1:
+               self->cancelpoint--;
+               break;
+       default:
+               self->canceldisable += x;
+       }
 }
 
 /* "rsyscall" is a mechanism by which a thread can synchronously force all
index 23c38851a5910fe88aad2205dd35154d41708277..a85cc800f7c64f8736133c2fad6ec6bff3ee791f 100644 (file)
@@ -3,8 +3,8 @@
 int pthread_setcancelstate(int new, int *old)
 {
        struct pthread *self = pthread_self();
-       if (old) *old = self->canceldisable;
+       if (old) *old = self->canceldisable & 1;
        if ((unsigned)new > 1) return EINVAL;
-       self->canceldisable = new;
+       self->canceldisable = (self->canceldisable & ~1) | new;
        return 0;
 }