public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org
Subject: Re: [PATCH 3/3] nptl: Move cancel type out of cancelhandling
Date: Thu, 16 Apr 2020 11:18:31 -0300	[thread overview]
Message-ID: <6c1b2cb4-9fcc-f83c-1f56-66b1ea032f3a@linaro.org> (raw)
In-Reply-To: <20200401142439.1906574-3-adhemerval.zanella@linaro.org>

Ping.

On 01/04/2020 11:24, Adhemerval Zanella wrote:
> The thread cancellation type is not accessed concurrently internally
> neither its pthread interface allows changing the state of a different
> thread than its own.
> 
> It allows simplifing the cancellation wrappers and the
> CANCEL_CANCELED_AND_ASYNCHRONOUS is removed.
> 
> Checked on x86_64-linux-gnu.
> ---
>  nptl/allocatestack.c         |  1 +
>  nptl/cancellation.c          | 59 ++++++++++--------------------------
>  nptl/cleanup_defer.c         | 46 +++-------------------------
>  nptl/cleanup_defer_compat.c  | 46 +++-------------------------
>  nptl/descr.h                 | 13 ++------
>  nptl/nptl-init.c             |  2 +-
>  nptl/pthread_cancel.c        |  5 ++-
>  nptl/pthread_setcanceltype.c | 42 +++----------------------
>  nptl/pthread_testcancel.c    |  2 +-
>  9 files changed, 41 insertions(+), 175 deletions(-)
> 
> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
> index d9174274c2..481487bbb4 100644
> --- a/nptl/allocatestack.c
> +++ b/nptl/allocatestack.c
> @@ -233,6 +233,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;
>  
>    /* No pending event.  */
> diff --git a/nptl/cancellation.c b/nptl/cancellation.c
> index 7e8cbe9fe1..7127f9ae91 100644
> --- a/nptl/cancellation.c
> +++ b/nptl/cancellation.c
> @@ -32,31 +32,18 @@ attribute_hidden
>  __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 | EXITING_BITMASK | TERMINATED_BITMASK))
> +	  == CANCELED_BITMASK)
> +    {
> +      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
> +      __do_cancel ();
>      }
>  
>    return oldval;
> @@ -70,36 +57,22 @@ __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;
> -    }
> +  THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_DEFERRED);
>  
>    /* 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 & (CANCELING_BITMASK | CANCELED_BITMASK))
> -			   == CANCELING_BITMASK, 0))
> +  int ch = THREAD_GETMEM (self, cancelhandling);
> +  while (__glibc_unlikely ((ch & (CANCELING_BITMASK | CANCELED_BITMASK))
> +			    == CANCELING_BITMASK))
>      {
> -      futex_wait_simple ((unsigned int *) &self->cancelhandling, newval,
> +      futex_wait_simple ((unsigned int *) &self->cancelhandling, ch,
>  			 FUTEX_PRIVATE);
> -      newval = THREAD_GETMEM (self, cancelhandling);
> +      ch = THREAD_GETMEM (self, cancelhandling);
>      }
>  }
> diff --git a/nptl/cleanup_defer.c b/nptl/cleanup_defer.c
> index 33d4ea6eef..3300b4df46 100644
> --- a/nptl/cleanup_defer.c
> +++ b/nptl/cleanup_defer.c
> @@ -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);
> @@ -67,25 +49,7 @@ __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 ();
>  }
> diff --git a/nptl/cleanup_defer_compat.c b/nptl/cleanup_defer_compat.c
> index a1ad291fcc..77655c1b0a 100644
> --- a/nptl/cleanup_defer_compat.c
> +++ b/nptl/cleanup_defer_compat.c
> @@ -29,27 +29,9 @@ _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
>    buffer->__arg = arg;
>    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);
>  }
> @@ -64,27 +46,9 @@ _pthread_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;
> -	}
> -
> -      __pthread_testcancel ();
> -    }
> +  THREAD_SETMEM (self, canceltype, buffer->__canceltype);
> +  if (buffer->__canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
> +    __pthread_testcancel ();
>  
>    /* If necessary call the cleanup routine after we removed the
>       current cleanup block from the list.  */
> diff --git a/nptl/descr.h b/nptl/descr.h
> index 61665bf859..bae9457e33 100644
> --- a/nptl/descr.h
> +++ b/nptl/descr.h
> @@ -269,9 +269,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 canceling has been initiated.  */
>  #define CANCELING_BIT		2
>  #define CANCELING_BITMASK	(0x01 << CANCELING_BIT)
> @@ -287,13 +284,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;
> @@ -391,6 +381,9 @@ struct pthread
>    /* Thread cancel state (enable, disable).  */
>    unsigned char cancelstate;
>  
> +  /* Thread cancel type (deferred, asynchronous).  */
> +  unsigned char canceltype;
> +
>    /* This member must be last.  */
>    char end_padding[];
>  
> diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
> index 96b1444a01..89f58d2e5e 100644
> --- a/nptl/nptl-init.c
> +++ b/nptl/nptl-init.c
> @@ -157,7 +157,7 @@ sigcancel_handler (int sig, siginfo_t *si, void *ctx)
>  	  THREAD_SETMEM (self, result, PTHREAD_CANCELED);
>  
>  	  /* Make sure asynchronous cancellation is still enabled.  */
> -	  if ((newval & CANCELTYPE_BITMASK) != 0)
> +	  if (self->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
>  	    /* Run the registered destructors and terminate the thread.  */
>  	    __do_cancel ();
>  
> diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
> index 5b2789d620..7518c0b8bf 100644
> --- a/nptl/pthread_cancel.c
> +++ b/nptl/pthread_cancel.c
> @@ -56,7 +56,10 @@ __pthread_cancel (pthread_t th)
>  	 signal.  We avoid this if possible since it's more
>  	 expensive.  */
>        if (pd->cancelstate == PTHREAD_CANCEL_ENABLE
> -	  && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval))
> +	  && pd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS
> +	  && (newval & (CANCELED_BITMASK | EXITING_BITMASK
> +			| TERMINATED_BITMASK))
> +	      == CANCELED_BITMASK)
>  	{
>  	  /* Mark the cancellation as "in progress".  */
>  	  if (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling,
> diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c
> index cc0507ae04..d8cb54736d 100644
> --- a/nptl/pthread_setcanceltype.c
> +++ b/nptl/pthread_setcanceltype.c
> @@ -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;
>  }
> diff --git a/nptl/pthread_testcancel.c b/nptl/pthread_testcancel.c
> index 3ffff4ebef..026c20f82e 100644
> --- a/nptl/pthread_testcancel.c
> +++ b/nptl/pthread_testcancel.c
> @@ -34,5 +34,5 @@ __pthread_testcancel (void)
>        __do_cancel ();
>      }
>  }
> -strong_alias (__pthread_testcancel, pthread_testcancel)
> +weak_alias (__pthread_testcancel, pthread_testcancel)
>  hidden_def (__pthread_testcancel)
> 

  reply	other threads:[~2020-04-16 14:18 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-01 14:24 [PATCH 1/3] nptl: Remove x86_64 cancellation assembly implementations Adhemerval Zanella
2020-04-01 14:24 ` [PATCH 2/3] nptl: Move cancel state out of cancelhandling Adhemerval Zanella
2020-04-16 14:18   ` Adhemerval Zanella
2020-04-22 14:11   ` Florian Weimer
2020-04-23 19:30     ` Adhemerval Zanella
2020-04-24 13:21       ` Florian Weimer
2020-04-30 11:11         ` Adhemerval Zanella
2020-05-12 14:47           ` Adhemerval Zanella
2020-05-12 14:57             ` Florian Weimer
2020-05-16 18:38   ` Florian Weimer
2020-05-20 14:51     ` Adhemerval Zanella
2020-04-01 14:24 ` [PATCH 3/3] nptl: Move cancel type " Adhemerval Zanella
2020-04-16 14:18   ` Adhemerval Zanella [this message]
2020-04-02 12:23 ` [PATCH 1/3] nptl: Remove x86_64 cancellation assembly implementations Adhemerval Zanella
2020-04-02 12:27 ` H.J. Lu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6c1b2cb4-9fcc-f83c-1f56-66b1ea032f3a@linaro.org \
    --to=adhemerval.zanella@linaro.org \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).