|  | /* futex operations for glibc-internal use.  NaCl version. | 
|  | Copyright (C) 2014-2016 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 */ |