futex-internal.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /* futex operations for glibc-internal use. Linux version.
  2. Copyright (C) 2014-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #ifndef FUTEX_INTERNAL_H
  16. #define FUTEX_INTERNAL_H
  17. #include <sysdeps/nptl/futex-internal.h>
  18. #include <errno.h>
  19. #include <lowlevellock-futex.h>
  20. #include <nptl/pthreadP.h>
  21. /* See sysdeps/nptl/futex-internal.h for documentation; this file only
  22. contains Linux-specific comments.
  23. The Linux kernel treats provides absolute timeouts based on the
  24. CLOCK_REALTIME clock and relative timeouts measured against the
  25. CLOCK_MONOTONIC clock.
  26. We expect a Linux kernel version of 2.6.22 or more recent (since this
  27. version, EINTR is not returned on spurious wake-ups anymore). */
  28. /* FUTEX_SHARED is always supported by the Linux kernel. */
  29. static __always_inline int
  30. futex_supports_pshared (int pshared)
  31. {
  32. if (__glibc_likely (pshared == PTHREAD_PROCESS_PRIVATE))
  33. return 0;
  34. else if (pshared == PTHREAD_PROCESS_SHARED)
  35. return 0;
  36. else
  37. return EINVAL;
  38. }
  39. /* The Linux kernel supports relative timeouts measured against the
  40. CLOCK_MONOTONIC clock. */
  41. static __always_inline bool
  42. futex_supports_exact_relative_timeouts (void)
  43. {
  44. return true;
  45. }
  46. /* See sysdeps/nptl/futex-internal.h for details. */
  47. static __always_inline int
  48. futex_wait (unsigned int *futex_word, unsigned int expected, int private)
  49. {
  50. int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
  51. switch (err)
  52. {
  53. case 0:
  54. case -EAGAIN:
  55. case -EINTR:
  56. return -err;
  57. case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */
  58. case -EFAULT: /* Must have been caused by a glibc or application bug. */
  59. case -EINVAL: /* Either due to wrong alignment or due to the timeout not
  60. being normalized. Must have been caused by a glibc or
  61. application bug. */
  62. case -ENOSYS: /* Must have been caused by a glibc bug. */
  63. /* No other errors are documented at this time. */
  64. default:
  65. futex_fatal_error ();
  66. }
  67. }
  68. /* See sysdeps/nptl/futex-internal.h for details. */
  69. static __always_inline int
  70. futex_wait_cancelable (unsigned int *futex_word, unsigned int expected,
  71. int private)
  72. {
  73. int oldtype;
  74. oldtype = __pthread_enable_asynccancel ();
  75. int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
  76. __pthread_disable_asynccancel (oldtype);
  77. switch (err)
  78. {
  79. case 0:
  80. case -EAGAIN:
  81. case -EINTR:
  82. return -err;
  83. case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */
  84. case -EFAULT: /* Must have been caused by a glibc or application bug. */
  85. case -EINVAL: /* Either due to wrong alignment or due to the timeout not
  86. being normalized. Must have been caused by a glibc or
  87. application bug. */
  88. case -ENOSYS: /* Must have been caused by a glibc bug. */
  89. /* No other errors are documented at this time. */
  90. default:
  91. futex_fatal_error ();
  92. }
  93. }
  94. /* See sysdeps/nptl/futex-internal.h for details. */
  95. static __always_inline int
  96. futex_reltimed_wait (unsigned int *futex_word, unsigned int expected,
  97. const struct timespec *reltime, int private)
  98. {
  99. int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
  100. switch (err)
  101. {
  102. case 0:
  103. case -EAGAIN:
  104. case -EINTR:
  105. case -ETIMEDOUT:
  106. return -err;
  107. case -EFAULT: /* Must have been caused by a glibc or application bug. */
  108. case -EINVAL: /* Either due to wrong alignment or due to the timeout not
  109. being normalized. Must have been caused by a glibc or
  110. application bug. */
  111. case -ENOSYS: /* Must have been caused by a glibc bug. */
  112. /* No other errors are documented at this time. */
  113. default:
  114. futex_fatal_error ();
  115. }
  116. }
  117. /* See sysdeps/nptl/futex-internal.h for details. */
  118. static __always_inline int
  119. futex_reltimed_wait_cancelable (unsigned int *futex_word,
  120. unsigned int expected,
  121. const struct timespec *reltime, int private)
  122. {
  123. int oldtype;
  124. oldtype = LIBC_CANCEL_ASYNC ();
  125. int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
  126. LIBC_CANCEL_RESET (oldtype);
  127. switch (err)
  128. {
  129. case 0:
  130. case -EAGAIN:
  131. case -EINTR:
  132. case -ETIMEDOUT:
  133. return -err;
  134. case -EFAULT: /* Must have been caused by a glibc or application bug. */
  135. case -EINVAL: /* Either due to wrong alignment or due to the timeout not
  136. being normalized. Must have been caused by a glibc or
  137. application bug. */
  138. case -ENOSYS: /* Must have been caused by a glibc bug. */
  139. /* No other errors are documented at this time. */
  140. default:
  141. futex_fatal_error ();
  142. }
  143. }
  144. /* See sysdeps/nptl/futex-internal.h for details. */
  145. static __always_inline int
  146. futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
  147. const struct timespec *abstime, int private)
  148. {
  149. /* Work around the fact that the kernel rejects negative timeout values
  150. despite them being valid. */
  151. if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
  152. return ETIMEDOUT;
  153. int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
  154. FUTEX_CLOCK_REALTIME, private);
  155. switch (err)
  156. {
  157. case 0:
  158. case -EAGAIN:
  159. case -EINTR:
  160. case -ETIMEDOUT:
  161. return -err;
  162. case -EFAULT: /* Must have been caused by a glibc or application bug. */
  163. case -EINVAL: /* Either due to wrong alignment or due to the timeout not
  164. being normalized. Must have been caused by a glibc or
  165. application bug. */
  166. case -ENOSYS: /* Must have been caused by a glibc bug. */
  167. /* No other errors are documented at this time. */
  168. default:
  169. futex_fatal_error ();
  170. }
  171. }
  172. /* See sysdeps/nptl/futex-internal.h for details. */
  173. static __always_inline int
  174. futex_abstimed_wait_cancelable (unsigned int *futex_word,
  175. unsigned int expected,
  176. const struct timespec *abstime, int private)
  177. {
  178. /* Work around the fact that the kernel rejects negative timeout values
  179. despite them being valid. */
  180. if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
  181. return ETIMEDOUT;
  182. int oldtype;
  183. oldtype = __pthread_enable_asynccancel ();
  184. int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
  185. FUTEX_CLOCK_REALTIME, private);
  186. __pthread_disable_asynccancel (oldtype);
  187. switch (err)
  188. {
  189. case 0:
  190. case -EAGAIN:
  191. case -EINTR:
  192. case -ETIMEDOUT:
  193. return -err;
  194. case -EFAULT: /* Must have been caused by a glibc or application bug. */
  195. case -EINVAL: /* Either due to wrong alignment or due to the timeout not
  196. being normalized. Must have been caused by a glibc or
  197. application bug. */
  198. case -ENOSYS: /* Must have been caused by a glibc bug. */
  199. /* No other errors are documented at this time. */
  200. default:
  201. futex_fatal_error ();
  202. }
  203. }
  204. /* See sysdeps/nptl/futex-internal.h for details. */
  205. static __always_inline void
  206. futex_wake (unsigned int *futex_word, int processes_to_wake, int private)
  207. {
  208. int res = lll_futex_wake (futex_word, processes_to_wake, private);
  209. /* No error. Ignore the number of woken processes. */
  210. if (res >= 0)
  211. return;
  212. switch (res)
  213. {
  214. case -EFAULT: /* Could have happened due to memory reuse. */
  215. case -EINVAL: /* Could be either due to incorrect alignment (a bug in
  216. glibc or in the application) or due to memory being
  217. reused for a PI futex. We cannot distinguish between the
  218. two causes, and one of them is correct use, so we do not
  219. act in this case. */
  220. return;
  221. case -ENOSYS: /* Must have been caused by a glibc bug. */
  222. /* No other errors are documented at this time. */
  223. default:
  224. futex_fatal_error ();
  225. }
  226. }
  227. #endif /* futex-internal.h */