Blame nptl/cancellation.c

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include "pthreadP.h"
Packit 6c4009
#include <futex-internal.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The next two functions are similar to pthread_setcanceltype() but
Packit 6c4009
   more specialized for the use in the cancelable functions like write().
Packit 6c4009
   They do not need to check parameters etc.  */
Packit 6c4009
int
Packit 6c4009
attribute_hidden
Packit 6c4009
__pthread_enable_asynccancel (void)
Packit 6c4009
{
Packit 6c4009
  struct pthread *self = THREAD_SELF;
Packit 6c4009
  int oldval = THREAD_GETMEM (self, cancelhandling);
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      int newval = oldval | CANCELTYPE_BITMASK;
Packit 6c4009
Packit 6c4009
      if (newval == oldval)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
Packit 6c4009
					      oldval);
Packit 6c4009
      if (__glibc_likely (curval == oldval))
Packit 6c4009
	{
Packit 6c4009
	  if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
Packit 6c4009
	    {
Packit 6c4009
	      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
Packit 6c4009
	      __do_cancel ();
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Prepare the next round.  */
Packit 6c4009
      oldval = curval;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return oldval;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
attribute_hidden
Packit 6c4009
__pthread_disable_asynccancel (int oldtype)
Packit 6c4009
{
Packit 6c4009
  /* If asynchronous cancellation was enabled before we do not have
Packit 6c4009
     anything to do.  */
Packit 6c4009
  if (oldtype & CANCELTYPE_BITMASK)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  struct pthread *self = THREAD_SELF;
Packit 6c4009
  int newval;
Packit 6c4009
Packit 6c4009
  int oldval = THREAD_GETMEM (self, cancelhandling);
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      newval = oldval & ~CANCELTYPE_BITMASK;
Packit 6c4009
Packit 6c4009
      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
Packit 6c4009
					      oldval);
Packit 6c4009
      if (__glibc_likely (curval == oldval))
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* Prepare the next round.  */
Packit 6c4009
      oldval = curval;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We cannot return when we are being canceled.  Upon return the
Packit 6c4009
     thread might be things which would have to be undone.  The
Packit 6c4009
     following loop should loop until the cancellation signal is
Packit 6c4009
     delivered.  */
Packit 6c4009
  while (__builtin_expect ((newval & (CANCELING_BITMASK | CANCELED_BITMASK))
Packit 6c4009
			   == CANCELING_BITMASK, 0))
Packit 6c4009
    {
Packit 6c4009
      futex_wait_simple ((unsigned int *) &self->cancelhandling, newval,
Packit 6c4009
			 FUTEX_PRIVATE);
Packit 6c4009
      newval = THREAD_GETMEM (self, cancelhandling);
Packit 6c4009
    }
Packit 6c4009
}