about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nptl/ChangeLog6
-rw-r--r--nptl/cancellation.c14
-rw-r--r--nptl/libc-cancellation.c14
3 files changed, 32 insertions, 2 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index b83dfd0c9d..74a2a73666 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -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
diff --git a/nptl/cancellation.c b/nptl/cancellation.c
index 81134a679a..4d528cfc2f 100644
--- a/nptl/cancellation.c
+++ b/nptl/cancellation.c
@@ -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);
+    }
 }
diff --git a/nptl/libc-cancellation.c b/nptl/libc-cancellation.c
index cf24f1c0f2..35ac82b3d1 100644
--- a/nptl/libc-cancellation.c
+++ b/nptl/libc-cancellation.c
@@ -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);
+    }
 }