/* futex operations for glibc-internal use. NaCl version. 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 . */ #ifndef FUTEX_INTERNAL_H #define FUTEX_INTERNAL_H #include #include #include #include #include /* See sysdeps/nptl/futex-internal.h for documentation; this file only contains NaCl-specific comments. There is no support yet for shared futexes nor for exact relative timeouts. */ /* See sysdeps/nptl/futex-internal.h for constraints on the value of the FUTEX_PRIVATE and FUTEX_SHARED constants. Shared futexes are not yet supported, and we never allow clients to actually request shared futexes. Therefore, we do not need a different value. */ #undef FUTEX_SHARED #define FUTEX_SHARED FUTEX_PRIVATE /* FUTEX_SHARED is not yet supported. */ 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 ENOTSUP; else return EINVAL; } /* Relative timeouts are only emulated via absolute timeouts using the system clock. */ static __always_inline bool futex_supports_exact_relative_timeouts (void) { return false; } /* 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 = __pthread_enable_asynccancel (); int err = lll_futex_timed_wait (futex_word, expected, reltime, 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 int futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, const struct timespec *abstime, int private) { int err = __nacl_irt_futex.futex_wait_abs ((volatile int *) futex_word, expected, abstime); 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_wait_cancelable (unsigned int *futex_word, unsigned int expected, const struct timespec *abstime, int private) { int oldtype; oldtype = __pthread_enable_asynccancel (); int err = __nacl_irt_futex.futex_wait_abs ((volatile int *) futex_word, expected, abstime); __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 */