No cancel signal in unsafe places.

When disabling async cancellation we cannot return from the function
call if the thread is canceled.  This happens when the cancel bits
have been set before async cancel is disabled but the signal hasn't
been sent/received yet.  Delay for as long as necessary since
otherwise the signal might be received in an unsafe context.
This commit is contained in:
Ulrich Drepper 2009-05-15 10:12:35 -07:00
parent 2e180a2622
commit b1e74e1d80
3 changed files with 32 additions and 2 deletions

View File

@ -1,3 +1,9 @@
2009-05-15 Ulrich Drepper <drepper@redhat.com>
* cancellation.c (__pthread_disable_asynccancel): Don't return if
thread is canceled.
* libc-cancellation.c (__libc_disable_asynccancel): Likewise.
2009-04-27 Ulrich Drepper <drepper@redhat.com> 2009-04-27 Ulrich Drepper <drepper@redhat.com>
* cancellation.c (__pthread_disable_asynccancel): Use THREAD_ATOMIC_AND * cancellation.c (__pthread_disable_asynccancel): Use THREAD_ATOMIC_AND

View File

@ -70,15 +70,17 @@ __pthread_disable_asynccancel (int oldtype)
return; return;
struct pthread *self = THREAD_SELF; struct pthread *self = THREAD_SELF;
int newval;
#ifdef THREAD_ATOMIC_AND #ifdef THREAD_ATOMIC_AND
THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK); THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK);
newval = THREAD_GETMEM (self, cancelhandling);
#else #else
int oldval = THREAD_GETMEM (self, cancelhandling); int oldval = THREAD_GETMEM (self, cancelhandling);
while (1) while (1)
{ {
int newval = oldval & ~CANCELTYPE_BITMASK; newval = oldval & ~CANCELTYPE_BITMASK;
if (newval == oldval) if (newval == oldval)
break; break;
@ -92,4 +94,14 @@ __pthread_disable_asynccancel (int oldtype)
oldval = curval; oldval = curval;
} }
#endif #endif
/* We cannot return when we are being canceled. Upon return the
thread might be things which would have to be undone. The
following loop should loop until the cancellation signal is
delivered. */
while (__builtin_expect (newval & CANCELED_BITMASK, 0))
{
lll_futex_wait (&self->cancelhandling, newval, LLL_PRIVATE);
newval = THREAD_GETMEM (self, cancelhandling);
}
} }

View File

@ -86,15 +86,17 @@ __libc_disable_asynccancel (int oldtype)
return; return;
struct pthread *self = THREAD_SELF; struct pthread *self = THREAD_SELF;
int newval;
#ifdef THREAD_ATOMIC_AND #ifdef THREAD_ATOMIC_AND
THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK); THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK);
newval = THREAD_GETMEM (self, cancelhandling);
#else #else
int oldval = THREAD_GETMEM (self, cancelhandling); int oldval = THREAD_GETMEM (self, cancelhandling);
while (1) while (1)
{ {
int newval = oldval & ~CANCELTYPE_BITMASK; newval = oldval & ~CANCELTYPE_BITMASK;
if (newval == oldval) if (newval == oldval)
break; break;
@ -108,6 +110,16 @@ __libc_disable_asynccancel (int oldtype)
oldval = curval; oldval = curval;
} }
#endif #endif
/* We cannot return when we are being canceled. Upon return the
thread might be things which would have to be undone. The
following loop should loop until the cancellation signal is
delivered. */
while (__builtin_expect (newval & CANCELED_BITMASK, 0))
{
lll_futex_wait (&self->cancelhandling, newval, LLL_PRIVATE);
newval = THREAD_GETMEM (self, cancelhandling);
}
} }