1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-06-13 19:21:36 +03:00
Files
glibc/sysdeps/unix/sysv/linux/futex-internal.h
Mike Crowe 99d01ffcc3 nptl: Add clockid parameter to futex timed wait calls
In preparation for adding POSIX clockwait variants of timedwait functions,
add a clockid_t parameter to futex_abstimed_wait functions and pass
CLOCK_REALTIME from all callers for the time being.

Replace lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset
which takes a clockid_t parameter rather than the magic clockbit.

	* sysdeps/nptl/lowlevellock-futex.h,
	sysdeps/unix/sysv/linux/lowlevellock-futex.h: Replace
	lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset that
	takes a clockid rather than a special clockbit.
	* sysdeps/nptl/lowlevellock-futex.h: Add
	lll_futex_supported_clockid so that client functions can check
	whether their clockid parameter is valid even if they don't
	ultimately end up calling lll_futex_clock_wait_bitset.
	* sysdeps/nptl/futex-internal.h,
	sysdeps/unix/sysv/linux/futex-internal.h
	(futex_abstimed_wait, futex_abstimed_wait_cancelable): Add
	clockid_t parameter to indicate which clock the absolute time
	passed should be measured against. Pass that clockid onto
	lll_futex_clock_wait_bitset. Add invalid clock as reason for
	returning -EINVAL.
	* sysdeps/nptl/futex-internal.h,
	sysdeps/unix/sysv/linux/futex-internal.h: Introduce
	futex_abstimed_supported_clockid so that client functions can check
	whether their clockid parameter is valid even if they don't
	ultimately end up calling futex_abstimed_wait.
	* nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Remove
	code to calculate relative timeout for
	__PTHREAD_COND_CLOCK_MONOTONIC_MASK and just pass CLOCK_MONOTONIC
	or CLOCK_REALTIME as required to futex_abstimed_wait_cancelable.
	* nptl/pthread_rwlock_common (__pthread_rwlock_rdlock_full)
	(__pthread_wrlock_full), nptl/sem_waitcommon (do_futex_wait): Pass
	additional CLOCK_REALTIME to futex_abstimed_wait_cancelable.
	* nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock):
	Switch to lll_futex_clock_wait_bitset and pass CLOCK_REALTIME

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2019-07-12 13:36:23 +00:00

264 lines
8.5 KiB
C

/* futex operations for glibc-internal use. Linux version.
Copyright (C) 2014-2019 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 FUTEX_INTERNAL_H
#define FUTEX_INTERNAL_H
#include <sysdeps/nptl/futex-internal.h>
#include <errno.h>
#include <lowlevellock-futex.h>
#include <sysdep-cancel.h>
/* See sysdeps/nptl/futex-internal.h for documentation; this file only
contains Linux-specific comments.
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). */
/* FUTEX_SHARED is always supported by the Linux kernel. */
static __always_inline int
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;
}
/* The Linux kernel supports relative timeouts measured against the
CLOCK_MONOTONIC clock. */
static __always_inline bool
futex_supports_exact_relative_timeouts (void)
{
return true;
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
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 ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_wait_cancelable (unsigned int *futex_word, unsigned int expected,
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 ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_reltimed_wait (unsigned int *futex_word, unsigned int expected,
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 ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_reltimed_wait_cancelable (unsigned int *futex_word,
unsigned int expected,
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 ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_abstimed_supported_clockid (clockid_t clockid)
{
return lll_futex_supported_clockid (clockid);
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
clockid_t clockid,
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 ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_abstimed_wait_cancelable (unsigned int *futex_word,
unsigned int expected,
clockid_t clockid,
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 ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline void
futex_wake (unsigned int *futex_word, int processes_to_wake, int private)
{
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 */