hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame sysdeps/nptl/futex-internal.h

Packit 6c4009
/* futex operations for glibc-internal use.  Stub version; do not include
Packit 6c4009
   this file directly.
Packit 6c4009
   Copyright (C) 2014-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
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
#ifndef STUB_FUTEX_INTERNAL_H
Packit 6c4009
#define STUB_FUTEX_INTERNAL_H
Packit 6c4009
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
/* This file defines futex operations used internally in glibc.  A futex
Packit 6c4009
   consists of the so-called futex word in userspace, which is of type
Packit 6c4009
   unsigned int and represents an application-specific condition, and kernel
Packit 6c4009
   state associated with this particular futex word (e.g., wait queues).  The
Packit 6c4009
   futex operations we provide are wrappers for the futex syscalls and add
Packit 6c4009
   glibc-specific error checking of the syscall return value.  We abort on
Packit 6c4009
   error codes that are caused by bugs in glibc or in the calling application,
Packit 6c4009
   or when an error code is not known.  We return error codes that can arise
Packit 6c4009
   in correct executions to the caller.  Each operation calls out exactly the
Packit 6c4009
   return values that callers need to handle.
Packit 6c4009
Packit 6c4009
   The private flag must be either FUTEX_PRIVATE or FUTEX_SHARED.
Packit 6c4009
   FUTEX_PRIVATE is always supported, and the implementation can internally
Packit 6c4009
   use FUTEX_SHARED when FUTEX_PRIVATE is requested.  FUTEX_SHARED is not
Packit 6c4009
   necessarily supported (use futex_supports_pshared to detect this).
Packit 6c4009
Packit 6c4009
   We expect callers to only use these operations if futexes and the
Packit 6c4009
   specific futex operations being used are supported (e.g., FUTEX_SHARED).
Packit 6c4009
Packit 6c4009
   Given that waking other threads waiting on a futex involves concurrent
Packit 6c4009
   accesses to the futex word, you must use atomic operations to access the
Packit 6c4009
   futex word.
Packit 6c4009
Packit 6c4009
   Both absolute and relative timeouts can be used.  An absolute timeout
Packit 6c4009
   expires when the given specific point in time on the CLOCK_REALTIME clock
Packit 6c4009
   passes, or when it already has passed.  A relative timeout expires when
Packit 6c4009
   the given duration of time on the CLOCK_MONOTONIC clock passes.  Relative
Packit 6c4009
   timeouts may be imprecise (see futex_supports_exact_relative_timeouts).
Packit 6c4009
Packit 6c4009
   Due to POSIX requirements on when synchronization data structures such
Packit 6c4009
   as mutexes or semaphores can be destroyed and due to the futex design
Packit 6c4009
   having separate fast/slow paths for wake-ups, we need to consider that
Packit 6c4009
   futex_wake calls might effectively target a data structure that has been
Packit 6c4009
   destroyed and reused for another object, or unmapped; thus, some
Packit 6c4009
   errors or spurious wake-ups can happen in correct executions that would
Packit 6c4009
   not be possible in a program using just a single futex whose lifetime
Packit 6c4009
   does not end before the program terminates.  For background, see:
Packit 6c4009
   https://sourceware.org/ml/libc-alpha/2014-04/msg00075.html
Packit 6c4009
   https://lkml.org/lkml/2014/11/27/472  */
Packit 6c4009
Packit 6c4009
/* Defined this way for interoperability with lowlevellock.
Packit 6c4009
   FUTEX_PRIVATE must be zero because the initializers for pthread_mutex_t,
Packit 6c4009
   pthread_rwlock_t, and pthread_cond_t initialize the respective field of
Packit 6c4009
   those structures to zero, and we want FUTEX_PRIVATE to be the default.  */
Packit 6c4009
#define FUTEX_PRIVATE LLL_PRIVATE
Packit 6c4009
#define FUTEX_SHARED  LLL_SHARED
Packit 6c4009
#if FUTEX_PRIVATE != 0
Packit 6c4009
# error FUTEX_PRIVATE must be equal to 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Returns EINVAL if PSHARED is neither PTHREAD_PROCESS_PRIVATE nor
Packit 6c4009
   PTHREAD_PROCESS_SHARED; otherwise, returns 0 if PSHARED is supported, and
Packit 6c4009
   ENOTSUP if not.  */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_supports_pshared (int pshared);
Packit 6c4009
Packit 6c4009
/* Returns true if relative timeouts are robust to concurrent changes to the
Packit 6c4009
   system clock.  If this returns false, relative timeouts can still be used
Packit 6c4009
   but might be effectively longer or shorter than requested.  */
Packit 6c4009
static __always_inline bool
Packit 6c4009
futex_supports_exact_relative_timeouts (void);
Packit 6c4009
Packit 6c4009
/* Atomically wrt other futex operations on the same futex, this blocks iff
Packit 6c4009
   the value *FUTEX_WORD matches the expected value.  This is
Packit 6c4009
   semantically equivalent to:
Packit 6c4009
     l = <get lock associated with futex> (FUTEX_WORD);
Packit 6c4009
     wait_flag = <get wait_flag associated with futex> (FUTEX_WORD);
Packit 6c4009
     lock (l);
Packit 6c4009
     val = atomic_load_relaxed (FUTEX_WORD);
Packit 6c4009
     if (val != expected) { unlock (l); return EAGAIN; }
Packit 6c4009
     atomic_store_relaxed (wait_flag, true);
Packit 6c4009
     unlock (l);
Packit 6c4009
     // Now block; can time out in futex_time_wait (see below)
Packit 6c4009
     while (atomic_load_relaxed(wait_flag) && !<spurious wake-up>);
Packit 6c4009
Packit 6c4009
   Note that no guarantee of a happens-before relation between a woken
Packit 6c4009
   futex_wait and a futex_wake is documented; however, this does not matter
Packit 6c4009
   in practice because we have to consider spurious wake-ups (see below),
Packit 6c4009
   and thus would not be able to reliably reason about which futex_wake woke
Packit 6c4009
   us.
Packit 6c4009
Packit 6c4009
   Returns 0 if woken by a futex operation or spuriously.  (Note that due to
Packit 6c4009
   the POSIX requirements mentioned above, we need to conservatively assume
Packit 6c4009
   that unrelated futex_wake operations could wake this futex; it is easiest
Packit 6c4009
   to just be prepared for spurious wake-ups.)
Packit 6c4009
   Returns EAGAIN if the futex word did not match the expected value.
Packit 6c4009
   Returns EINTR if waiting was interrupted by a signal.
Packit 6c4009
Packit 6c4009
   Note that some previous code in glibc assumed the underlying futex
Packit 6c4009
   operation (e.g., syscall) to start with or include the equivalent of a
Packit 6c4009
   seq_cst fence; this allows one to avoid an explicit seq_cst fence before
Packit 6c4009
   a futex_wait call when synchronizing similar to Dekker synchronization.
Packit 6c4009
   However, we make no such guarantee here.  */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_wait (unsigned int *futex_word, unsigned int expected, int private);
Packit 6c4009
Packit 6c4009
/* Like futex_wait but does not provide any indication why we stopped waiting.
Packit 6c4009
   Thus, when this function returns, you have to always check FUTEX_WORD to
Packit 6c4009
   determine whether you need to continue waiting, and you cannot detect
Packit 6c4009
   whether the waiting was interrupted by a signal.  Example use:
Packit 6c4009
     while (atomic_load_relaxed (&futex_word) == 23)
Packit 6c4009
       futex_wait_simple (&futex_word, 23, FUTEX_PRIVATE);
Packit 6c4009
   This is common enough to make providing this wrapper worthwhile.  */
Packit 6c4009
static __always_inline void
Packit 6c4009
futex_wait_simple (unsigned int *futex_word, unsigned int expected,
Packit 6c4009
		   int private)
Packit 6c4009
{
Packit 6c4009
  ignore_value (futex_wait (futex_word, expected, private));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Like futex_wait but is a POSIX cancellation point.  */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_wait_cancelable (unsigned int *futex_word, unsigned int expected,
Packit 6c4009
		       int private);
Packit 6c4009
Packit 6c4009
/* Like futex_wait, but will eventually time out (i.e., stop being
Packit 6c4009
   blocked) after the duration of time provided (i.e., RELTIME) has
Packit 6c4009
   passed.  The caller must provide a normalized RELTIME.  RELTIME can also
Packit 6c4009
   equal NULL, in which case this function behaves equivalent to futex_wait.
Packit 6c4009
Packit 6c4009
   Returns the same values as futex_wait under those same conditions;
Packit 6c4009
   additionally, returns ETIMEDOUT if the timeout expired.
Packit 6c4009
   */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_reltimed_wait (unsigned int* futex_word, unsigned int expected,
Packit 6c4009
		     const struct timespec* reltime, int private);
Packit 6c4009
Packit 6c4009
/* Like futex_reltimed_wait but is a POSIX cancellation point.  */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_reltimed_wait_cancelable (unsigned int* futex_word,
Packit 6c4009
				unsigned int expected,
Packit 6c4009
			        const struct timespec* reltime, int private);
Packit 6c4009
Packit 6c4009
/* Like futex_reltimed_wait, but the provided timeout (ABSTIME) is an
Packit 6c4009
   absolute point in time; a call will time out after this point in time.  */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_abstimed_wait (unsigned int* futex_word, unsigned int expected,
Packit 6c4009
		     const struct timespec* abstime, int private);
Packit 6c4009
Packit 6c4009
/* Like futex_reltimed_wait but is a POSIX cancellation point.  */
Packit 6c4009
static __always_inline int
Packit 6c4009
futex_abstimed_wait_cancelable (unsigned int* futex_word,
Packit 6c4009
				unsigned int expected,
Packit 6c4009
			        const struct timespec* abstime, int private);
Packit 6c4009
Packit 6c4009
/* Atomically wrt other futex operations on the same futex, this unblocks the
Packit 6c4009
   specified number of processes, or all processes blocked on this futex if
Packit 6c4009
   there are fewer than the specified number.  Semantically, this is
Packit 6c4009
   equivalent to:
Packit 6c4009
     l = <get lock associated with futex> (FUTEX_WORD);
Packit 6c4009
     lock (l);
Packit 6c4009
     for (res = 0; PROCESSES_TO_WAKE > 0; PROCESSES_TO_WAKE--, res++) {
Packit 6c4009
       if (<no process blocked on futex>) break;
Packit 6c4009
       wf = <get wait_flag of a process blocked on futex> (FUTEX_WORD);
Packit 6c4009
       // No happens-before guarantee with woken futex_wait (see above)
Packit 6c4009
       atomic_store_relaxed (wf, 0);
Packit 6c4009
     }
Packit 6c4009
     return res;
Packit 6c4009
Packit 6c4009
   Note that we need to support futex_wake calls to past futexes whose memory
Packit 6c4009
   has potentially been reused due to POSIX' requirements on synchronization
Packit 6c4009
   object destruction (see above); therefore, we must not report or abort
Packit 6c4009
   on most errors.  */
Packit 6c4009
static __always_inline void
Packit 6c4009
futex_wake (unsigned int* futex_word, int processes_to_wake, int private);
Packit 6c4009
Packit 6c4009
/* Calls __libc_fatal with an error message.  Convenience function for
Packit 6c4009
   concrete implementations of the futex interface.  */
Packit 6c4009
static __always_inline __attribute__ ((__noreturn__)) void
Packit 6c4009
futex_fatal_error (void)
Packit 6c4009
{
Packit 90011d
  __libc_fatal ("The futex facility returned an unexpected error code.\n");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif  /* futex-internal.h */