Blame nptl/pthread_join_common.c

Packit Service 82fcde
/* Common definition for pthread_{timed,try}join{_np}.
Packit Service 82fcde
   Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include "pthreadP.h"
Packit Service 82fcde
#include <atomic.h>
Packit Service 82fcde
#include <stap-probe.h>
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
cleanup (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  /* If we already changed the waiter ID, reset it.  The call cannot
Packit Service 82fcde
     fail for any reason but the thread not having done that yet so
Packit Service 82fcde
     there is no reason for a loop.  */
Packit Service 82fcde
  struct pthread *self = THREAD_SELF;
Packit Service 82fcde
  atomic_compare_exchange_weak_acquire (&arg, &self, NULL);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
__pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
Packit Service 82fcde
			const struct timespec *abstime, bool block)
Packit Service 82fcde
{
Packit Service 82fcde
  struct pthread *pd = (struct pthread *) threadid;
Packit Service 82fcde
Packit Service 82fcde
  /* Make sure the descriptor is valid.  */
Packit Service 82fcde
  if (INVALID_NOT_TERMINATED_TD_P (pd))
Packit Service 82fcde
    /* Not a valid thread handle.  */
Packit Service 82fcde
    return ESRCH;
Packit Service 82fcde
Packit Service 82fcde
  /* Is the thread joinable?.  */
Packit Service 82fcde
  if (IS_DETACHED (pd))
Packit Service 82fcde
    /* We cannot wait for the thread.  */
Packit Service 82fcde
    return EINVAL;
Packit Service 82fcde
Packit Service 82fcde
  struct pthread *self = THREAD_SELF;
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
Packit Service 82fcde
  LIBC_PROBE (pthread_join, 1, threadid);
Packit Service 82fcde
Packit Service 82fcde
  if ((pd == self
Packit Service 82fcde
       || (self->joinid == pd
Packit Service 82fcde
	   && (pd->cancelhandling
Packit Service 82fcde
	       & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
Packit Service 82fcde
		  | TERMINATED_BITMASK)) == 0))
Packit Service 82fcde
      && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling))
Packit Service 82fcde
    /* This is a deadlock situation.  The threads are waiting for each
Packit Service 82fcde
       other to finish.  Note that this is a "may" error.  To be 100%
Packit Service 82fcde
       sure we catch this error we would have to lock the data
Packit Service 82fcde
       structures but it is not necessary.  In the unlikely case that
Packit Service 82fcde
       two threads are really caught in this situation they will
Packit Service 82fcde
       deadlock.  It is the programmer's problem to figure this
Packit Service 82fcde
       out.  */
Packit Service 82fcde
    return EDEADLK;
Packit Service 82fcde
Packit Service 82fcde
  /* Wait for the thread to finish.  If it is already locked something
Packit Service 82fcde
     is wrong.  There can only be one waiter.  */
Packit Service 82fcde
  else if (__glibc_unlikely (atomic_compare_exchange_weak_acquire (&pd->joinid,
Packit Service 82fcde
								   &self,
Packit Service 82fcde
								   NULL)))
Packit Service 82fcde
    /* There is already somebody waiting for the thread.  */
Packit Service 82fcde
    return EINVAL;
Packit Service 82fcde
Packit Service 82fcde
  if (block)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* During the wait we change to asynchronous cancellation.  If we
Packit Service 82fcde
	 are cancelled the thread we are waiting for must be marked as
Packit Service 82fcde
	 un-wait-ed for again.  */
Packit Service 82fcde
      pthread_cleanup_push (cleanup, &pd->joinid);
Packit Service 82fcde
Packit Service 82fcde
      int oldtype = CANCEL_ASYNC ();
Packit Service 82fcde
Packit Service 82fcde
      if (abstime != NULL)
Packit Service 82fcde
	result = lll_timedwait_tid (pd->tid, abstime);
Packit Service 82fcde
      else
Packit Service 82fcde
	lll_wait_tid (pd->tid);
Packit Service 82fcde
Packit Service 82fcde
      CANCEL_RESET (oldtype);
Packit Service 82fcde
Packit Service 82fcde
      pthread_cleanup_pop (0);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_likely (result == 0))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We mark the thread as terminated and as joined.  */
Packit Service 82fcde
      pd->tid = -1;
Packit Service 82fcde
Packit Service 82fcde
      /* Store the return value if the caller is interested.  */
Packit Service 82fcde
      if (thread_return != NULL)
Packit Service 82fcde
	*thread_return = pd->result;
Packit Service 82fcde
Packit Service 82fcde
      /* Free the TCB.  */
Packit Service 82fcde
      __free_tcb (pd);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    pd->joinid = NULL;
Packit Service 82fcde
Packit Service 82fcde
  LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
hidden_def (__pthread_timedjoin_ex)