From: Rich Felker Date: Tue, 5 Apr 2011 22:00:28 +0000 (-0400) Subject: new framework to inhibit thread cancellation when needed X-Git-Tag: v0.7.7~8 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=729cb49f52c825ac44f437e1ff0865d9f0b3626a;p=oweals%2Fmusl.git new framework to inhibit thread cancellation when needed 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. --- diff --git a/src/internal/libc.h b/src/internal/libc.h index b80cbcc9..be88dc04 100644 --- a/src/internal/libc.h +++ b/src/internal/libc.h @@ -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 diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 284b45a0..52487001 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -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 diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c index 23c38851..a85cc800 100644 --- a/src/thread/pthread_setcancelstate.c +++ b/src/thread/pthread_setcancelstate.c @@ -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; }