| /* futex operations for glibc-internal use. NaCl version. |
| Copyright (C) 2014-2015 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 <nacl-interfaces.h> |
| #include <nptl/pthreadP.h> |
| |
| /* 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 */ |