]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
nptl: Move cancel type out of cancelhandling
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Tue, 31 Mar 2020 20:24:39 +0000 (17:24 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 9 Jun 2021 18:16:45 +0000 (15:16 -0300)
Now that the thread cancellation type is not accessed concurrently
anymore, it is possible to move it out the cancelhandling.

By removing the cancel state out of the internal thread cancel handling
state there is no need to check if cancelled bit was set in CAS
operation.

It allows simplifing the cancellation wrappers and the
CANCEL_CANCELED_AND_ASYNCHRONOUS is removed.

Checked on x86_64-linux-gnu and aarch64-linux-gnu.

nptl/allocatestack.c
nptl/cancellation.c
nptl/cleanup_defer.c
nptl/descr.h
nptl/libc-cleanup.c
nptl/pthread_cancel.c
nptl/pthread_setcanceltype.c
sysdeps/nptl/dl-tls_init_tp.c

index 54e95baad7171933294394fbd4ffb6455c87b76c..9be6c428948f6a44baa2c61822521a4d52f019c7 100644 (file)
@@ -161,6 +161,7 @@ get_cached_stack (size_t *sizep, void **memp)
   /* Cancellation handling is back to the default.  */
   result->cancelhandling = 0;
   result->cancelstate = PTHREAD_CANCEL_ENABLE;
+  result->canceltype = PTHREAD_CANCEL_DEFERRED;
   result->cleanup = NULL;
   result->setup_failed = 0;
 
index ce00603109b661b4a44bdc200953538e6eb6d215..05962784d51fb98b9d0a09710a230c52b0a426f4 100644 (file)
@@ -31,31 +31,19 @@ int
 __pthread_enable_asynccancel (void)
 {
   struct pthread *self = THREAD_SELF;
-  int oldval = THREAD_GETMEM (self, cancelhandling);
 
-  while (1)
-    {
-      int newval = oldval | CANCELTYPE_BITMASK;
-
-      if (newval == oldval)
-       break;
-
-      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
-                                             oldval);
-      if (__glibc_likely (curval == oldval))
-       {
-         if (self->cancelstate == PTHREAD_CANCEL_ENABLE
-             && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval))
-           {
-             THREAD_SETMEM (self, result, PTHREAD_CANCELED);
-             __do_cancel ();
-           }
+  int oldval = THREAD_GETMEM (self, canceltype);
+  THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
 
-         break;
-       }
+  int ch = THREAD_GETMEM (self, cancelhandling);
 
-      /* Prepare the next round.  */
-      oldval = curval;
+  if (self->cancelstate == PTHREAD_CANCEL_ENABLE
+      && (ch & CANCELED_BITMASK)
+      && !(ch & EXITING_BITMASK)
+      && !(ch & TERMINATED_BITMASK))
+    {
+      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+      __do_cancel ();
     }
 
   return oldval;
@@ -69,25 +57,10 @@ __pthread_disable_asynccancel (int oldtype)
 {
   /* If asynchronous cancellation was enabled before we do not have
      anything to do.  */
-  if (oldtype & CANCELTYPE_BITMASK)
+  if (oldtype == PTHREAD_CANCEL_ASYNCHRONOUS)
     return;
 
   struct pthread *self = THREAD_SELF;
-  int newval;
-
-  int oldval = THREAD_GETMEM (self, cancelhandling);
-
-  while (1)
-    {
-      newval = oldval & ~CANCELTYPE_BITMASK;
-
-      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
-                                             oldval);
-      if (__glibc_likely (curval == oldval))
-       break;
-
-      /* Prepare the next round.  */
-      oldval = curval;
-    }
+  self->canceltype = PTHREAD_CANCEL_DEFERRED;
 }
 libc_hidden_def (__pthread_disable_asynccancel)
index 873ab007fd4acb40ebb57d5fdfa67eaa5676b3f7..7e858d0df068276baa9a288b165550b735b907be 100644 (file)
@@ -31,27 +31,9 @@ ___pthread_register_cancel_defer (__pthread_unwind_buf_t *buf)
   ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
   ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup);
 
-  int cancelhandling = THREAD_GETMEM (self, cancelhandling);
-
   /* Disable asynchronous cancellation for now.  */
-  if (__glibc_unlikely (cancelhandling & CANCELTYPE_BITMASK))
-    while (1)
-      {
-       int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
-                                               cancelhandling
-                                               & ~CANCELTYPE_BITMASK,
-                                               cancelhandling);
-       if (__glibc_likely (curval == cancelhandling))
-         /* Successfully replaced the value.  */
-         break;
-
-       /* Prepare for the next round.  */
-       cancelhandling = curval;
-      }
-
-  ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK
-                               ? PTHREAD_CANCEL_ASYNCHRONOUS
-                               : PTHREAD_CANCEL_DEFERRED);
+  ibuf->priv.data.canceltype = THREAD_GETMEM (self, canceltype);
+  THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_DEFERRED);
 
   /* Store the new cleanup handler info.  */
   THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf);
@@ -73,27 +55,9 @@ ___pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf)
 
   THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev);
 
-  int cancelhandling;
-  if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED
-      && ((cancelhandling = THREAD_GETMEM (self, cancelhandling))
-         & CANCELTYPE_BITMASK) == 0)
-    {
-      while (1)
-       {
-         int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
-                                                 cancelhandling
-                                                 | CANCELTYPE_BITMASK,
-                                                 cancelhandling);
-         if (__glibc_likely (curval == cancelhandling))
-           /* Successfully replaced the value.  */
-           break;
-
-         /* Prepare for the next round.  */
-         cancelhandling = curval;
-       }
-
-      __pthread_testcancel ();
-    }
+  THREAD_SETMEM (self, canceltype, ibuf->priv.data.canceltype);
+  if (ibuf->priv.data.canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
+    __pthread_testcancel ();
 }
 versioned_symbol (libc, ___pthread_unregister_cancel_restore,
                  __pthread_unregister_cancel_restore, GLIBC_2_34);
index 35f5330e7fa3ccb42aaef91aa44c5ba84850eed4..c85778d44941a42f6a9e2161524968ea97117f88 100644 (file)
@@ -277,9 +277,6 @@ struct pthread
 
   /* Flags determining processing of cancellation.  */
   int cancelhandling;
-  /* Bit set if asynchronous cancellation mode is selected.  */
-#define CANCELTYPE_BIT         1
-#define CANCELTYPE_BITMASK     (0x01 << CANCELTYPE_BIT)
   /* Bit set if canceled.  */
 #define CANCELED_BIT           3
 #define CANCELED_BITMASK       (0x01 << CANCELED_BIT)
@@ -292,13 +289,6 @@ struct pthread
   /* Bit set if thread is supposed to change XID.  */
 #define SETXID_BIT             6
 #define SETXID_BITMASK         (0x01 << SETXID_BIT)
-  /* Mask for the rest.  Helps the compiler to optimize.  */
-#define CANCEL_RESTMASK                0xffffff80
-
-#define CANCEL_CANCELED_AND_ASYNCHRONOUS(value) \
-  (((value) & (CANCELTYPE_BITMASK | CANCELED_BITMASK    \
-              | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK))     \
-   == (CANCELTYPE_BITMASK | CANCELED_BITMASK))
 
   /* Flags.  Including those copied from the thread attribute.  */
   int flags;
@@ -402,6 +392,10 @@ struct pthread
      PTHREAD_CANCEL_DISABLE).  */
   unsigned char cancelstate;
 
+  /* Thread cancel type (PTHREAD_CANCEL_DEFERRED or
+     PTHREAD_CANCEL_ASYNCHRONOUS).  */
+  unsigned char canceltype;
+
   /* Used on strsignal.  */
   struct tls_internal_t tls_state;
 
index 6286b8b525177d765aa910a32ad971afdb2dd2e5..180d15bc9e9a836805ec4b8e6ae99d668b9eca92 100644 (file)
@@ -27,27 +27,9 @@ __libc_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer)
 
   buffer->__prev = THREAD_GETMEM (self, cleanup);
 
-  int cancelhandling = THREAD_GETMEM (self, cancelhandling);
-
   /* Disable asynchronous cancellation for now.  */
-  if (__glibc_unlikely (cancelhandling & CANCELTYPE_BITMASK))
-    while (1)
-      {
-       int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
-                                               cancelhandling
-                                               & ~CANCELTYPE_BITMASK,
-                                               cancelhandling);
-       if (__glibc_likely (curval == cancelhandling))
-         /* Successfully replaced the value.  */
-         break;
-
-       /* Prepare for the next round.  */
-       cancelhandling = curval;
-      }
-
-  buffer->__canceltype = (cancelhandling & CANCELTYPE_BITMASK
-                         ? PTHREAD_CANCEL_ASYNCHRONOUS
-                         : PTHREAD_CANCEL_DEFERRED);
+  buffer->__canceltype = THREAD_GETMEM (self, canceltype);
+  THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_DEFERRED);
 
   THREAD_SETMEM (self, cleanup, buffer);
 }
@@ -60,26 +42,8 @@ __libc_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer)
 
   THREAD_SETMEM (self, cleanup, buffer->__prev);
 
-  int cancelhandling;
-  if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0)
-      && ((cancelhandling = THREAD_GETMEM (self, cancelhandling))
-         & CANCELTYPE_BITMASK) == 0)
-    {
-      while (1)
-       {
-         int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
-                                                 cancelhandling
-                                                 | CANCELTYPE_BITMASK,
-                                                 cancelhandling);
-         if (__glibc_likely (curval == cancelhandling))
-           /* Successfully replaced the value.  */
-           break;
-
-         /* Prepare for the next round.  */
-         cancelhandling = curval;
-       }
-
+  THREAD_SETMEM (self, canceltype, buffer->__canceltype);
+  if (buffer->__canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
       __pthread_testcancel ();
-    }
 }
 libc_hidden_def (__libc_cleanup_pop_restore)
index f4f08363cfe62755914f443fcc05f088a27046ed..de4659a1f01c5fb9256262f6fe57a0485540aa20 100644 (file)
@@ -53,7 +53,7 @@ sigcancel_handler (int sig, siginfo_t *si, void *ctx)
   /* Set the return value.  */
   THREAD_SETMEM (self, result, PTHREAD_CANCELED);
   /* Make sure asynchronous cancellation is still enabled.  */
-  if ((ch & CANCELTYPE_BITMASK) != 0)
+  if (self->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
     __do_cancel ();
 }
 
@@ -104,8 +104,8 @@ __pthread_cancel (pthread_t th)
 #endif
 
       THREAD_SETMEM (pd, result, PTHREAD_CANCELED);
-      if ((oldch & CANCELSTATE_BITMASK) == 0
-         && (oldch & CANCELTYPE_BITMASK) != 0)
+      if (pd->cancelstate == PTHREAD_CANCEL_ENABLE
+         && pd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
        __do_cancel ();
       return 0;
     }
index ae5df1d5910b1e60403d76fbeb128a841a11a1e6..e7b24ae733dcc0f239cfff1fd58727c30a5b71a9 100644 (file)
@@ -29,43 +29,11 @@ __pthread_setcanceltype (int type, int *oldtype)
 
   volatile struct pthread *self = THREAD_SELF;
 
-  int oldval = THREAD_GETMEM (self, cancelhandling);
-  while (1)
-    {
-      int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS
-                   ? oldval | CANCELTYPE_BITMASK
-                   : oldval & ~CANCELTYPE_BITMASK);
-
-      /* Store the old value.  */
-      if (oldtype != NULL)
-       *oldtype = ((oldval & CANCELTYPE_BITMASK)
-                   ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED);
-
-      /* Avoid doing unnecessary work.  The atomic operation can
-        potentially be expensive if the memory has to be locked and
-        remote cache lines have to be invalidated.  */
-      if (oldval == newval)
-       break;
-
-      /* Update the cancel handling word.  This has to be done
-        atomically since other bits could be modified as well.  */
-      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
-                                             oldval);
-      if (__glibc_likely (curval == oldval))
-       {
-         if (self->cancelstate == PTHREAD_CANCEL_ENABLE
-             && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval))
-           {
-             THREAD_SETMEM (self, result, PTHREAD_CANCELED);
-             __do_cancel ();
-           }
-
-         break;
-       }
-
-      /* Prepare for the next round.  */
-      oldval = curval;
-    }
+  if (oldtype != NULL)
+    *oldtype = self->canceltype;
+  self->canceltype = type;
+  if (type == PTHREAD_CANCEL_ASYNCHRONOUS)
+    __pthread_testcancel ();
 
   return 0;
 }
index 378b26a2f5b3cb5ae77432c4ee006ca00dc35d6f..b7b3bb1cdbbaba93855fbcd773d612da9ecf5071 100644 (file)
@@ -96,4 +96,5 @@ __tls_init_tp (void)
   THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
 
   THREAD_SETMEM (pd, cancelstate, PTHREAD_CANCEL_ENABLE);
+  THREAD_SETMEM (pd, canceltype, PTHREAD_CANCEL_DEFERRED);
 }