glibc/sysdeps/nptl/futex-internal.h

204 lines
9.4 KiB
C

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