|
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 Service |
88f876 |
__libc_fatal ("The futex facility returned an unexpected error code.\n");
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#endif /* futex-internal.h */
|