Blame nptl/pthread_cond_broadcast.c

Packit Service 82fcde
/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
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 <endian.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
#include <futex-internal.h>
Packit Service 82fcde
#include <pthread.h>
Packit Service 82fcde
#include <pthreadP.h>
Packit Service 82fcde
#include <stap-probe.h>
Packit Service 82fcde
#include <atomic.h>
Packit Service 82fcde
Packit Service 82fcde
#include <shlib-compat.h>
Packit Service 82fcde
Packit Service 82fcde
#include "pthread_cond_common.c"
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* We do the following steps from __pthread_cond_signal in one critical
Packit Service 82fcde
   section: (1) signal all waiters in G1, (2) close G1 so that it can become
Packit Service 82fcde
   the new G2 and make G2 the new G1, and (3) signal all waiters in the new
Packit Service 82fcde
   G1.  We don't need to do all these steps if there are no waiters in G1
Packit Service 82fcde
   and/or G2.  See __pthread_cond_signal for further details.  */
Packit Service 82fcde
int
Packit Service 82fcde
__pthread_cond_broadcast (pthread_cond_t *cond)
Packit Service 82fcde
{
Packit Service 82fcde
  LIBC_PROBE (cond_broadcast, 1, cond);
Packit Service 82fcde
Packit Service 82fcde
  unsigned int wrefs = atomic_load_relaxed (&cond->__data.__wrefs);
Packit Service 82fcde
  if (wrefs >> 3 == 0)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
  int private = __condvar_get_private (wrefs);
Packit Service 82fcde
Packit Service 82fcde
  __condvar_acquire_lock (cond, private);
Packit Service 82fcde
Packit Service 82fcde
  unsigned long long int wseq = __condvar_load_wseq_relaxed (cond);
Packit Service 82fcde
  unsigned int g2 = wseq & 1;
Packit Service 82fcde
  unsigned int g1 = g2 ^ 1;
Packit Service 82fcde
  wseq >>= 1;
Packit Service 82fcde
  bool do_futex_wake = false;
Packit Service 82fcde
Packit Service 82fcde
  /* Step (1): signal all waiters remaining in G1.  */
Packit Service 82fcde
  if (cond->__data.__g_size[g1] != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Add as many signals as the remaining size of the group.  */
Packit Service 82fcde
      atomic_fetch_add_relaxed (cond->__data.__g_signals + g1,
Packit Service 82fcde
				cond->__data.__g_size[g1] << 1);
Packit Service 82fcde
      cond->__data.__g_size[g1] = 0;
Packit Service 82fcde
Packit Service 82fcde
      /* We need to wake G1 waiters before we quiesce G1 below.  */
Packit Service 82fcde
      /* TODO Only set it if there are indeed futex waiters.  We could
Packit Service 82fcde
	 also try to move this out of the critical section in cases when
Packit Service 82fcde
	 G2 is empty (and we don't need to quiesce).  */
Packit Service 82fcde
      futex_wake (cond->__data.__g_signals + g1, INT_MAX, private);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* G1 is complete.  Step (2) is next unless there are no waiters in G2, in
Packit Service 82fcde
     which case we can stop.  */
Packit Service 82fcde
  if (__condvar_quiesce_and_switch_g1 (cond, wseq, &g1, private))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Step (3): Send signals to all waiters in the old G2 / new G1.  */
Packit Service 82fcde
      atomic_fetch_add_relaxed (cond->__data.__g_signals + g1,
Packit Service 82fcde
				cond->__data.__g_size[g1] << 1);
Packit Service 82fcde
      cond->__data.__g_size[g1] = 0;
Packit Service 82fcde
      /* TODO Only set it if there are indeed futex waiters.  */
Packit Service 82fcde
      do_futex_wake = true;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __condvar_release_lock (cond, private);
Packit Service 82fcde
Packit Service 82fcde
  if (do_futex_wake)
Packit Service 82fcde
    futex_wake (cond->__data.__g_signals + g1, INT_MAX, private);
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
Packit Service 82fcde
		  GLIBC_2_3_2);