]> sourceware.org Git - glibc.git/commitdiff
No cancel signal in unsafe places.
authorUlrich Drepper <drepper@redhat.com>
Fri, 15 May 2009 17:12:35 +0000 (10:12 -0700)
committerUlrich Drepper <drepper@redhat.com>
Fri, 15 May 2009 17:12:35 +0000 (10:12 -0700)
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.

nptl/ChangeLog
nptl/cancellation.c
nptl/libc-cancellation.c

index b83dfd0c9d87bc482169dbb8edca91b106cd404c..74a2a73666b7e3e6628aeb635b6d74b670470894 100644 (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>
 
        * cancellation.c (__pthread_disable_asynccancel): Use THREAD_ATOMIC_AND
index 81134a679a90f7b3b552d6155a8e5059f44edd02..4d528cfc2f6a4d1cd737c7508e0b36af9ffdef08 100644 (file)
@@ -70,15 +70,17 @@ __pthread_disable_asynccancel (int oldtype)
     return;
 
   struct pthread *self = THREAD_SELF;
+  int newval;
 
 #ifdef THREAD_ATOMIC_AND
   THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK);
+  newval = THREAD_GETMEM (self, cancelhandling);
 #else
   int oldval = THREAD_GETMEM (self, cancelhandling);
 
   while (1)
     {
-      int newval = oldval & ~CANCELTYPE_BITMASK;
+      newval = oldval & ~CANCELTYPE_BITMASK;
 
       if (newval == oldval)
        break;
@@ -92,4 +94,14 @@ __pthread_disable_asynccancel (int oldtype)
       oldval = curval;
     }
 #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);
+    }
 }
index cf24f1c0f2171c2ab993e878e59f1445a62e5cb3..35ac82b3d1bd1e07eeae54d24167005588352d66 100644 (file)
@@ -86,15 +86,17 @@ __libc_disable_asynccancel (int oldtype)
     return;
 
   struct pthread *self = THREAD_SELF;
+  int newval;
 
 #ifdef THREAD_ATOMIC_AND
   THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK);
+  newval = THREAD_GETMEM (self, cancelhandling);
 #else
   int oldval = THREAD_GETMEM (self, cancelhandling);
 
   while (1)
     {
-      int newval = oldval & ~CANCELTYPE_BITMASK;
+      newval = oldval & ~CANCELTYPE_BITMASK;
 
       if (newval == oldval)
        break;
@@ -108,6 +110,16 @@ __libc_disable_asynccancel (int oldtype)
       oldval = curval;
     }
 #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);
+    }
 }
 
 
This page took 0.056979 seconds and 5 git commands to generate.