This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/5] Consolidate futex-internal.h


On 10/30/19 4:00 PM, Adhemerval Zanella wrote:
> 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.

OK for master.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  sysdeps/nptl/futex-internal.h            | 211 +++++++++++++++++--
>  sysdeps/unix/sysv/linux/futex-internal.h | 255 -----------------------
>  2 files changed, 196 insertions(+), 270 deletions(-)
>  delete mode 100644 sysdeps/unix/sysv/linux/futex-internal.h
> 
> 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 */
> diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h
> deleted file mode 100644
> index 5a4f4ff818..0000000000
> --- a/sysdeps/unix/sysv/linux/futex-internal.h
> +++ /dev/null
> @@ -1,255 +0,0 @@
> -/* 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
> -   <https://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;
> -}
> -
> -/* 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 */
> 


-- 
Cheers,
Carlos.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]