[hurd,commited] hurd: Take cancel_lock in critical section

Samuel Thibault <[email protected]>
Newsgroups gmane.os.hurd.cvs,gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
read/write etc. shall be signal-safe, and take cancel_lock, so we have to
defer signal delivery while holding cancel_lock.

Reported-by: Michael Banck <[email protected]>
---
 htl/cancellation.c                  |  5 +++++
 htl/pt-cancel.c                     | 14 +++++++++++++-
 htl/pt-internal.h                   |  2 +-
 htl/pt-setcancelstate.c             |  3 +++
 htl/pt-setcanceltype.c              |  3 +++
 htl/pt-testcancel.c                 |  3 +++
 sysdeps/htl/pt-cond-timedwait.c     |  4 ++++
 sysdeps/mach/hurd/htl/pt-docancel.c |  5 ++++-
 8 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/htl/cancellation.c b/htl/cancellation.c
index ba3b82bbb7..272c4a70b6 100644
--- a/htl/cancellation.c
+++ b/htl/cancellation.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library;  if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <hurd/signal.h>
 #include <pthread.h>
 #include <pthreadP.h>
 #include <pt-internal.h>
@@ -25,10 +26,12 @@ int __pthread_enable_asynccancel (void)
   struct __pthread *p = _pthread_self ();
   int oldtype;
 
+  HURD_CRITICAL_BEGIN;
   __pthread_mutex_lock (&p->cancel_lock);
   oldtype = p->cancel_type;
   p->cancel_type = PTHREAD_CANCEL_ASYNCHRONOUS;
   __pthread_mutex_unlock (&p->cancel_lock);
+  HURD_CRITICAL_END;
 
   __pthread_testcancel ();
 
@@ -39,7 +42,9 @@ void __pthread_disable_asynccancel (int oldtype)
 {
   struct __pthread *p = _pthread_self ();
 
+  HURD_CRITICAL_BEGIN;
   __pthread_mutex_lock (&p->cancel_lock);
   p->cancel_type = oldtype;
   __pthread_mutex_unlock (&p->cancel_lock);
+  HURD_CRITICAL_END;
 }
diff --git a/htl/pt-cancel.c b/htl/pt-cancel.c
index b376575742..b80c6018be 100644
--- a/htl/pt-cancel.c
+++ b/htl/pt-cancel.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library;  if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <hurd/signal.h>
 #include <pthread.h>
 
 #include <pt-internal.h>
@@ -27,15 +28,22 @@ __pthread_cancel (pthread_t t)
 {
   int err = 0;
   struct __pthread *p;
+  struct __pthread *self = _pthread_self ();
+  void *hurd_critical = NULL;
 
   p = __pthread_getid (t);
   if (p == NULL)
     return ESRCH;
 
+  if (p == self)
+    hurd_critical = _hurd_critical_section_lock ();
+
   __pthread_mutex_lock (&p->cancel_lock);
   if (p->cancel_pending)
     {
       __pthread_mutex_unlock (&p->cancel_lock);
+      if (p == self)
+	_hurd_critical_section_unlock (hurd_critical);
       return 0;
     }
 
@@ -44,12 +52,14 @@ __pthread_cancel (pthread_t t)
   if (p->cancel_state != PTHREAD_CANCEL_ENABLE)
     {
       __pthread_mutex_unlock (&p->cancel_lock);
+      if (p == self)
+	_hurd_critical_section_unlock (hurd_critical);
       return 0;
     }
 
   if (p->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS)
     /* CANCEL_LOCK is unlocked by this call.  */
-    err = __pthread_do_cancel (p);
+    err = __pthread_do_cancel (p, hurd_critical);
   else
     {
       if (p->cancel_hook != NULL)
@@ -59,6 +69,8 @@ __pthread_cancel (pthread_t t)
 
       __pthread_mutex_unlock (&p->cancel_lock);
     }
+  if (p == self)
+    _hurd_critical_section_unlock (hurd_critical);
 
   return err;
 }
diff --git a/htl/pt-internal.h b/htl/pt-internal.h
index e23e7bccc3..5a3104830c 100644
--- a/htl/pt-internal.h
+++ b/htl/pt-internal.h
@@ -292,7 +292,7 @@ libc_hidden_proto (__pthread_wakeup)
 
 /* Perform a cancelation.  The CANCEL_LOCK member of the given thread must
    be locked before calling this function, which must unlock it.  */
-extern int __pthread_do_cancel (struct __pthread *thread);
+extern int __pthread_do_cancel (struct __pthread *thread, void *hurd_critical);
 
 
 /* Initialize the thread specific data structures.  THREAD must be the
diff --git a/htl/pt-setcancelstate.c b/htl/pt-setcancelstate.c
index 6e42c35741..69a4cc825c 100644
--- a/htl/pt-setcancelstate.c
+++ b/htl/pt-setcancelstate.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library;  if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <hurd/signal.h>
 #include <pthread.h>
 #include <shlib-compat.h>
 #include <pt-internal.h>
@@ -35,6 +36,7 @@ __pthread_setcancelstate (int state, int *oldstate)
       break;
     }
 
+  HURD_CRITICAL_BEGIN;
   __pthread_mutex_lock (&p->cancel_lock);
   if (oldstate != NULL)
     *oldstate = p->cancel_state;
@@ -44,6 +46,7 @@ __pthread_setcancelstate (int state, int *oldstate)
     /* Do not achieve cancel when called again, notably from __pthread_exit itself.  */
     p->cancel_pending = 2;
   __pthread_mutex_unlock (&p->cancel_lock);
+  HURD_CRITICAL_END;
 
   if (cancelled)
     __pthread_exit (PTHREAD_CANCELED);
diff --git a/htl/pt-setcanceltype.c b/htl/pt-setcanceltype.c
index e71f2fc2fd..dd02aea75c 100644
--- a/htl/pt-setcanceltype.c
+++ b/htl/pt-setcanceltype.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library;  if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <hurd/signal.h>
 #include <pthread.h>
 #include <shlib-compat.h>
 #include <pt-internal.h>
@@ -35,12 +36,14 @@ __pthread_setcanceltype (int type, int *oldtype)
       break;
     }
 
+  HURD_CRITICAL_BEGIN;
   __pthread_mutex_lock (&p->cancel_lock);
   if (oldtype != NULL)
     *oldtype = p->cancel_type;
   p->cancel_type = type;
   cancelled = (p->cancel_state == PTHREAD_CANCEL_ENABLE) && p->cancel_pending && (p->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS);
   __pthread_mutex_unlock (&p->cancel_lock);
+  HURD_CRITICAL_END;
 
   if (cancelled)
     __pthread_exit (PTHREAD_CANCELED);
diff --git a/htl/pt-testcancel.c b/htl/pt-testcancel.c
index 6fb27f91ca..a8c17ef479 100644
--- a/htl/pt-testcancel.c
+++ b/htl/pt-testcancel.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library;  if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <hurd/signal.h>
 #include <pthread.h>
 
 #include <pt-internal.h>
@@ -28,9 +29,11 @@ __pthread_testcancel (void)
   struct __pthread *p = _pthread_self ();
   int cancelled;
 
+  HURD_CRITICAL_BEGIN;
   __pthread_mutex_lock (&p->cancel_lock);
   cancelled = (p->cancel_state == PTHREAD_CANCEL_ENABLE) && p->cancel_pending;
   __pthread_mutex_unlock (&p->cancel_lock);
+  HURD_CRITICAL_END;
 
   if (cancelled)
     __pthread_exit (PTHREAD_CANCELED);
diff --git a/sysdeps/htl/pt-cond-timedwait.c b/sysdeps/htl/pt-cond-timedwait.c
index 3920af3b8b..d350868c2b 100644
--- a/sysdeps/htl/pt-cond-timedwait.c
+++ b/sysdeps/htl/pt-cond-timedwait.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library;  if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <hurd/signal.h>
 #include <pthread.h>
 #include <shlib-compat.h>
 #include <pt-internal.h>
@@ -117,6 +118,7 @@ __pthread_cond_timedwait_internal (pthread_cond_t *cond,
 
      This function contains inline implementations of pthread_testcancel and
      pthread_setcanceltype to reduce locking overhead.  */
+  HURD_CRITICAL_BEGIN;
   __pthread_mutex_lock (&self->cancel_lock);
   cancelled = (self->cancel_state == PTHREAD_CANCEL_ENABLE)
       && self->cancel_pending;
@@ -124,6 +126,7 @@ __pthread_cond_timedwait_internal (pthread_cond_t *cond,
   if (cancelled)
     {
       __pthread_mutex_unlock (&self->cancel_lock);
+      HURD_CRITICAL_UNLOCK;
       __pthread_exit (PTHREAD_CANCELED);
     }
 
@@ -145,6 +148,7 @@ __pthread_cond_timedwait_internal (pthread_cond_t *cond,
   __pthread_spin_unlock (&cond->__lock);
 
   __pthread_mutex_unlock (&self->cancel_lock);
+  HURD_CRITICAL_END;
 
   /* Increase the waiter reference count.  Relaxed MO is sufficient because
      we only need to synchronize when decrementing the reference count.
diff --git a/sysdeps/mach/hurd/htl/pt-docancel.c b/sysdeps/mach/hurd/htl/pt-docancel.c
index a4167708c3..709f2507bd 100644
--- a/sysdeps/mach/hurd/htl/pt-docancel.c
+++ b/sysdeps/mach/hurd/htl/pt-docancel.c
@@ -29,8 +29,9 @@ call_exit (void)
 }
 
 int
-__pthread_do_cancel (struct __pthread *p)
+__pthread_do_cancel (struct __pthread *p, void *hurd_critical)
 {
+  struct __pthread *self = _pthread_self ();
   mach_port_t ktid;
   int me;
 
@@ -38,6 +39,8 @@ __pthread_do_cancel (struct __pthread *p)
   assert (p->cancel_state == PTHREAD_CANCEL_ENABLE);
 
   __pthread_mutex_unlock (&p->cancel_lock);
+  if (p == self)
+    _hurd_critical_section_unlock (hurd_critical);
 
   ktid = __mach_thread_self ();
   me = p->kernel_thread == ktid;
-- 
2.51.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.