aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/nptl/futex-internal.h
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-10-29 18:52:19 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-10-31 11:08:54 -0300
commitb865eed0ac73e385b32de7f97003f44e4798b8d4 (patch)
treeb0fcbdfdef23330ddcec388a7a4b990e12fd25c8 /sysdeps/nptl/futex-internal.h
parentff12e0fb91b9072800f031cb21fb2651ee7b6251 (diff)
downloadglibc-b865eed0ac73e385b32de7f97003f44e4798b8d4.tar
glibc-b865eed0ac73e385b32de7f97003f44e4798b8d4.tar.gz
glibc-b865eed0ac73e385b32de7f97003f44e4798b8d4.tar.bz2
glibc-b865eed0ac73e385b32de7f97003f44e4798b8d4.zip
Consolidate futex-internal.h
NPTL is already Linux specific, there is no need to parametrize futex operations and add a sysdep Linux specific implementation. This patch moves the relevant Linux code to nptl one. Checked on x86_64-linux-gnu and i686-linux-gnu. Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'sysdeps/nptl/futex-internal.h')
-rw-r--r--sysdeps/nptl/futex-internal.h211
1 files changed, 196 insertions, 15 deletions
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
index 4e6e8fa324..76921466f0 100644
--- a/sysdeps/nptl/futex-internal.h
+++ b/sysdeps/nptl/futex-internal.h
@@ -74,11 +74,35 @@
# error FUTEX_PRIVATE must be equal to 0
#endif
+/* 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.\n");
+}
+
+
+/* The Linux kernel treats provides absolute timeouts based on the
+ CLOCK_REALTIME clock and relative timeouts measured against the
+ CLOCK_MONOTONIC clock.
+
+ We expect a Linux kernel version of 2.6.22 or more recent (since this
+ version, EINTR is not returned on spurious wake-ups anymore). */
+
/* 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);
+futex_supports_pshared (int pshared)
+{
+ if (__glibc_likely (pshared == PTHREAD_PROCESS_PRIVATE))
+ return 0;
+ else if (pshared == PTHREAD_PROCESS_SHARED)
+ return 0;
+ else
+ return EINVAL;
+}
/* Atomically wrt other futex operations on the same futex, this blocks iff
the value *FUTEX_WORD matches the expected value. This is
@@ -112,7 +136,27 @@ futex_supports_pshared (int pshared);
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);
+futex_wait (unsigned int *futex_word, unsigned int expected, int private)
+{
+ int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ return -err;
+
+ case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -EINVAL: /* Either due to wrong alignment or due to the timeout not
+ being normalized. Must have been caused by a glibc or
+ application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
/* 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
@@ -132,7 +176,30 @@ futex_wait_simple (unsigned int *futex_word, unsigned int expected,
/* 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);
+ int private)
+{
+ int oldtype;
+ oldtype = __pthread_enable_asynccancel ();
+ int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
+ __pthread_disable_asynccancel (oldtype);
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ return -err;
+
+ case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -EINVAL: /* Either due to wrong alignment or due to the timeout not
+ being normalized. Must have been caused by a glibc or
+ application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
/* Like futex_wait, but will eventually time out (i.e., stop being
blocked) after the duration of time provided (i.e., RELTIME) has
@@ -144,32 +211,134 @@ futex_wait_cancelable (unsigned int *futex_word, unsigned int expected,
*/
static __always_inline int
futex_reltimed_wait (unsigned int* futex_word, unsigned int expected,
- const struct timespec* reltime, int private);
+ const struct timespec* reltime, int private)
+{
+ int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ case -ETIMEDOUT:
+ return -err;
+
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -EINVAL: /* Either due to wrong alignment or due to the timeout not
+ being normalized. Must have been caused by a glibc or
+ application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
/* 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);
+ const struct timespec* reltime, int private)
+{
+ int oldtype;
+ oldtype = LIBC_CANCEL_ASYNC ();
+ int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
+ LIBC_CANCEL_RESET (oldtype);
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ case -ETIMEDOUT:
+ return -err;
+
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -EINVAL: /* Either due to wrong alignment or due to the timeout not
+ being normalized. Must have been caused by a glibc or
+ application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
/* Check whether the specified clockid is supported by
futex_abstimed_wait and futex_abstimed_wait_cancelable. */
static __always_inline int
-futex_abstimed_supported_clockid (clockid_t clockid);
+futex_abstimed_supported_clockid (clockid_t clockid)
+{
+ return lll_futex_supported_clockid (clockid);
+}
/* 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,
clockid_t clockid,
- const struct timespec* abstime, int private);
+ const struct timespec* abstime, int private)
+{
+ /* Work around the fact that the kernel rejects negative timeout values
+ despite them being valid. */
+ if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
+ return ETIMEDOUT;
+ int err = lll_futex_clock_wait_bitset (futex_word, expected,
+ clockid, abstime,
+ private);
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ case -ETIMEDOUT:
+ return -err;
+
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -EINVAL: /* Either due to wrong alignment, unsupported
+ clockid or due to the timeout not being
+ normalized. Must have been caused by a glibc or
+ application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
/* 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,
clockid_t clockid,
- const struct timespec* abstime, int private);
+ const struct timespec* abstime, int private)
+{
+ /* Work around the fact that the kernel rejects negative timeout values
+ despite them being valid. */
+ if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
+ return ETIMEDOUT;
+ int oldtype;
+ oldtype = __pthread_enable_asynccancel ();
+ int err = lll_futex_clock_wait_bitset (futex_word, expected,
+ clockid, abstime,
+ private);
+ __pthread_disable_asynccancel (oldtype);
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ case -ETIMEDOUT:
+ return -err;
+
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -EINVAL: /* Either due to wrong alignment or due to the timeout not
+ being normalized. Must have been caused by a glibc or
+ application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
/* Atomically wrt other futex operations on the same futex, this unblocks the
specified number of processes, or all processes blocked on this futex if
@@ -190,14 +359,26 @@ futex_abstimed_wait_cancelable (unsigned int* futex_word,
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)
+futex_wake (unsigned int* futex_word, int processes_to_wake, int private)
{
- __libc_fatal ("The futex facility returned an unexpected error code.\n");
+ int res = lll_futex_wake (futex_word, processes_to_wake, private);
+ /* No error. Ignore the number of woken processes. */
+ if (res >= 0)
+ return;
+ switch (res)
+ {
+ case -EFAULT: /* Could have happened due to memory reuse. */
+ case -EINVAL: /* Could be either due to incorrect alignment (a bug in
+ glibc or in the application) or due to memory being
+ reused for a PI futex. We cannot distinguish between the
+ two causes, and one of them is correct use, so we do not
+ act in this case. */
+ return;
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
}
#endif /* futex-internal.h */