lowlevellock.S 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* Copyright (C) 2002-2006, 2007, 2009 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
  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. #include <sysdep.h>
  16. #include <pthread-errnos.h>
  17. #include <bits/kernel-features.h>
  18. #include <lowlevellock.h>
  19. #include <tcb-offsets.h>
  20. .text
  21. #ifdef __ASSUME_PRIVATE_FUTEX
  22. # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
  23. movl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
  24. # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
  25. movl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
  26. # define LOAD_FUTEX_WAIT(reg) \
  27. xorl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
  28. # define LOAD_FUTEX_WAIT_ABS(reg) \
  29. xorl $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
  30. # define LOAD_FUTEX_WAKE(reg) \
  31. xorl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
  32. #else
  33. # if FUTEX_WAIT == 0
  34. # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
  35. movl %fs:PRIVATE_FUTEX, reg
  36. # else
  37. # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
  38. movl %fs:PRIVATE_FUTEX, reg ; \
  39. orl $FUTEX_WAIT, reg
  40. # endif
  41. # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
  42. movl %fs:PRIVATE_FUTEX, reg ; \
  43. orl $FUTEX_WAKE, reg
  44. # if FUTEX_WAIT == 0
  45. # define LOAD_FUTEX_WAIT(reg) \
  46. xorl $FUTEX_PRIVATE_FLAG, reg ; \
  47. andl %fs:PRIVATE_FUTEX, reg
  48. # else
  49. # define LOAD_FUTEX_WAIT(reg) \
  50. xorl $FUTEX_PRIVATE_FLAG, reg ; \
  51. andl %fs:PRIVATE_FUTEX, reg ; \
  52. orl $FUTEX_WAIT, reg
  53. # endif
  54. # define LOAD_FUTEX_WAIT_ABS(reg) \
  55. xorl $FUTEX_PRIVATE_FLAG, reg ; \
  56. andl %fs:PRIVATE_FUTEX, reg ; \
  57. orl $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
  58. # define LOAD_FUTEX_WAKE(reg) \
  59. xorl $FUTEX_PRIVATE_FLAG, reg ; \
  60. andl %fs:PRIVATE_FUTEX, reg ; \
  61. orl $FUTEX_WAKE, reg
  62. #endif
  63. /* For the calculation see asm/vsyscall.h. */
  64. #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
  65. .globl __lll_lock_wait_private
  66. .type __lll_lock_wait_private,@function
  67. .hidden __lll_lock_wait_private
  68. #ifndef IS_IN_libpthread
  69. .weak __lll_lock_wait_private
  70. #endif
  71. .align 16
  72. __lll_lock_wait_private:
  73. cfi_startproc
  74. pushq %r10
  75. cfi_adjust_cfa_offset(8)
  76. pushq %rdx
  77. cfi_adjust_cfa_offset(8)
  78. cfi_offset(%r10, -16)
  79. cfi_offset(%rdx, -24)
  80. xorq %r10, %r10 /* No timeout. */
  81. movl $2, %edx
  82. LOAD_PRIVATE_FUTEX_WAIT (%esi)
  83. cmpl %edx, %eax /* NB: %edx == 2 */
  84. jne 2f
  85. 1: movl $SYS_futex, %eax
  86. syscall
  87. 2: movl %edx, %eax
  88. xchgl %eax, (%rdi) /* NB: lock is implied */
  89. testl %eax, %eax
  90. jnz 1b
  91. popq %rdx
  92. cfi_adjust_cfa_offset(-8)
  93. cfi_restore(%rdx)
  94. popq %r10
  95. cfi_adjust_cfa_offset(-8)
  96. cfi_restore(%r10)
  97. retq
  98. cfi_endproc
  99. .size __lll_lock_wait_private,.-__lll_lock_wait_private
  100. #ifdef NOT_IN_libc
  101. .globl __lll_lock_wait
  102. .type __lll_lock_wait,@function
  103. .hidden __lll_lock_wait
  104. .align 16
  105. __lll_lock_wait:
  106. cfi_startproc
  107. pushq %r10
  108. cfi_adjust_cfa_offset(8)
  109. pushq %rdx
  110. cfi_adjust_cfa_offset(8)
  111. cfi_offset(%r10, -16)
  112. cfi_offset(%rdx, -24)
  113. xorq %r10, %r10 /* No timeout. */
  114. movl $2, %edx
  115. LOAD_FUTEX_WAIT (%esi)
  116. cmpl %edx, %eax /* NB: %edx == 2 */
  117. jne 2f
  118. 1: movl $SYS_futex, %eax
  119. syscall
  120. 2: movl %edx, %eax
  121. xchgl %eax, (%rdi) /* NB: lock is implied */
  122. testl %eax, %eax
  123. jnz 1b
  124. popq %rdx
  125. cfi_adjust_cfa_offset(-8)
  126. cfi_restore(%rdx)
  127. popq %r10
  128. cfi_adjust_cfa_offset(-8)
  129. cfi_restore(%r10)
  130. retq
  131. cfi_endproc
  132. .size __lll_lock_wait,.-__lll_lock_wait
  133. /* %rdi: futex
  134. %rsi: flags
  135. %rdx: timeout
  136. %eax: futex value
  137. */
  138. .globl __lll_timedlock_wait
  139. .type __lll_timedlock_wait,@function
  140. .hidden __lll_timedlock_wait
  141. .align 16
  142. __lll_timedlock_wait:
  143. cfi_startproc
  144. # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
  145. # ifdef __PIC__
  146. cmpl $0, __have_futex_clock_realtime@GOTOFF(%rip)
  147. # else
  148. cmpl $0, __have_futex_clock_realtime
  149. # endif
  150. je .Lreltmo
  151. # endif
  152. pushq %r9
  153. cfi_adjust_cfa_offset(8)
  154. cfi_rel_offset(%r9, 0)
  155. movq %rdx, %r10
  156. movl $0xffffffff, %r9d
  157. LOAD_FUTEX_WAIT_ABS (%esi)
  158. movl $2, %edx
  159. cmpl %edx, %eax
  160. jne 2f
  161. 1: movl $SYS_futex, %eax
  162. movl $2, %edx
  163. syscall
  164. 2: xchgl %edx, (%rdi) /* NB: lock is implied */
  165. testl %edx, %edx
  166. jz 3f
  167. cmpl $-ETIMEDOUT, %eax
  168. je 4f
  169. cmpl $-EINVAL, %eax
  170. jne 1b
  171. 4: movl %eax, %edx
  172. negl %edx
  173. 3: movl %edx, %eax
  174. popq %r9
  175. cfi_adjust_cfa_offset(-8)
  176. cfi_restore(%r9)
  177. retq
  178. # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
  179. .Lreltmo:
  180. /* Check for a valid timeout value. */
  181. cmpq $1000000000, 8(%rdx)
  182. jae 3f
  183. pushq %r8
  184. cfi_adjust_cfa_offset(8)
  185. pushq %r9
  186. cfi_adjust_cfa_offset(8)
  187. pushq %r12
  188. cfi_adjust_cfa_offset(8)
  189. pushq %r13
  190. cfi_adjust_cfa_offset(8)
  191. pushq %r14
  192. cfi_adjust_cfa_offset(8)
  193. cfi_offset(%r8, -16)
  194. cfi_offset(%r9, -24)
  195. cfi_offset(%r12, -32)
  196. cfi_offset(%r13, -40)
  197. cfi_offset(%r14, -48)
  198. pushq %rsi
  199. cfi_adjust_cfa_offset(8)
  200. /* Stack frame for the timespec and timeval structs. */
  201. subq $24, %rsp
  202. cfi_adjust_cfa_offset(24)
  203. movq %rdi, %r12
  204. movq %rdx, %r13
  205. movl $2, %edx
  206. xchgl %edx, (%r12)
  207. testl %edx, %edx
  208. je 6f
  209. 1:
  210. /* Get current time. */
  211. movq %rsp, %rdi
  212. xorl %esi, %esi
  213. movq $VSYSCALL_ADDR_vgettimeofday, %rax
  214. /* This is a regular function call, all caller-save registers
  215. might be clobbered. */
  216. callq *%rax
  217. /* Compute relative timeout. */
  218. movq 8(%rsp), %rax
  219. movl $1000, %edi
  220. mul %rdi /* Milli seconds to nano seconds. */
  221. movq (%r13), %rdi
  222. movq 8(%r13), %rsi
  223. subq (%rsp), %rdi
  224. subq %rax, %rsi
  225. jns 4f
  226. addq $1000000000, %rsi
  227. decq %rdi
  228. 4: testq %rdi, %rdi
  229. js 2f /* Time is already up. */
  230. /* Store relative timeout. */
  231. movq %rdi, (%rsp)
  232. movq %rsi, 8(%rsp)
  233. /* Futex call. */
  234. movl $2, %edx
  235. movl $1, %eax
  236. movq %rsp, %r10
  237. movl 24(%rsp), %esi
  238. LOAD_FUTEX_WAIT (%esi)
  239. movq %r12, %rdi
  240. movl $SYS_futex, %eax
  241. syscall
  242. /* NB: %edx == 2 */
  243. xchgl %edx, (%r12)
  244. testl %edx, %edx
  245. je 6f
  246. cmpl $-ETIMEDOUT, %eax
  247. jne 1b
  248. 2: movl $ETIMEDOUT, %edx
  249. 6: addq $32, %rsp
  250. cfi_adjust_cfa_offset(-32)
  251. popq %r14
  252. cfi_adjust_cfa_offset(-8)
  253. cfi_restore(%r14)
  254. popq %r13
  255. cfi_adjust_cfa_offset(-8)
  256. cfi_restore(%r13)
  257. popq %r12
  258. cfi_adjust_cfa_offset(-8)
  259. cfi_restore(%r12)
  260. popq %r9
  261. cfi_adjust_cfa_offset(-8)
  262. cfi_restore(%r9)
  263. popq %r8
  264. cfi_adjust_cfa_offset(-8)
  265. cfi_restore(%r8)
  266. movl %edx, %eax
  267. retq
  268. 3: movl $EINVAL, %eax
  269. retq
  270. # endif
  271. cfi_endproc
  272. .size __lll_timedlock_wait,.-__lll_timedlock_wait
  273. #endif
  274. .globl __lll_unlock_wake_private
  275. .type __lll_unlock_wake_private,@function
  276. .hidden __lll_unlock_wake_private
  277. #ifndef IS_IN_libpthread
  278. .weak __lll_unlock_wake_private
  279. #endif
  280. .align 16
  281. __lll_unlock_wake_private:
  282. cfi_startproc
  283. pushq %rsi
  284. cfi_adjust_cfa_offset(8)
  285. pushq %rdx
  286. cfi_adjust_cfa_offset(8)
  287. cfi_offset(%rsi, -16)
  288. cfi_offset(%rdx, -24)
  289. movl $0, (%rdi)
  290. LOAD_PRIVATE_FUTEX_WAKE (%esi)
  291. movl $1, %edx /* Wake one thread. */
  292. movl $SYS_futex, %eax
  293. syscall
  294. popq %rdx
  295. cfi_adjust_cfa_offset(-8)
  296. cfi_restore(%rdx)
  297. popq %rsi
  298. cfi_adjust_cfa_offset(-8)
  299. cfi_restore(%rsi)
  300. retq
  301. cfi_endproc
  302. .size __lll_unlock_wake_private,.-__lll_unlock_wake_private
  303. #ifdef NOT_IN_libc
  304. .globl __lll_unlock_wake
  305. .type __lll_unlock_wake,@function
  306. .hidden __lll_unlock_wake
  307. .align 16
  308. __lll_unlock_wake:
  309. cfi_startproc
  310. pushq %rsi
  311. cfi_adjust_cfa_offset(8)
  312. pushq %rdx
  313. cfi_adjust_cfa_offset(8)
  314. cfi_offset(%rsi, -16)
  315. cfi_offset(%rdx, -24)
  316. movl $0, (%rdi)
  317. LOAD_FUTEX_WAKE (%esi)
  318. movl $1, %edx /* Wake one thread. */
  319. movl $SYS_futex, %eax
  320. syscall
  321. popq %rdx
  322. cfi_adjust_cfa_offset(-8)
  323. cfi_restore(%rdx)
  324. popq %rsi
  325. cfi_adjust_cfa_offset(-8)
  326. cfi_restore(%rsi)
  327. retq
  328. cfi_endproc
  329. .size __lll_unlock_wake,.-__lll_unlock_wake
  330. .globl __lll_timedwait_tid
  331. .type __lll_timedwait_tid,@function
  332. .hidden __lll_timedwait_tid
  333. .align 16
  334. __lll_timedwait_tid:
  335. cfi_startproc
  336. pushq %r12
  337. cfi_adjust_cfa_offset(8)
  338. pushq %r13
  339. cfi_adjust_cfa_offset(8)
  340. cfi_offset(%r12, -16)
  341. cfi_offset(%r13, -24)
  342. movq %rdi, %r12
  343. movq %rsi, %r13
  344. subq $16, %rsp
  345. cfi_adjust_cfa_offset(16)
  346. /* Get current time. */
  347. 2: movq %rsp, %rdi
  348. xorl %esi, %esi
  349. movq $VSYSCALL_ADDR_vgettimeofday, %rax
  350. callq *%rax
  351. /* Compute relative timeout. */
  352. movq 8(%rsp), %rax
  353. movl $1000, %edi
  354. mul %rdi /* Milli seconds to nano seconds. */
  355. movq (%r13), %rdi
  356. movq 8(%r13), %rsi
  357. subq (%rsp), %rdi
  358. subq %rax, %rsi
  359. jns 5f
  360. addq $1000000000, %rsi
  361. decq %rdi
  362. 5: testq %rdi, %rdi
  363. js 6f /* Time is already up. */
  364. movq %rdi, (%rsp) /* Store relative timeout. */
  365. movq %rsi, 8(%rsp)
  366. movl (%r12), %edx
  367. testl %edx, %edx
  368. jz 4f
  369. movq %rsp, %r10
  370. /* XXX The kernel so far uses global futex for the wakeup at
  371. all times. */
  372. #if FUTEX_WAIT == 0
  373. xorl %esi, %esi
  374. #else
  375. movl $FUTEX_WAIT, %esi
  376. #endif
  377. movq %r12, %rdi
  378. movl $SYS_futex, %eax
  379. syscall
  380. cmpl $0, (%rdi)
  381. jne 1f
  382. 4: xorl %eax, %eax
  383. 8: addq $16, %rsp
  384. cfi_adjust_cfa_offset(-16)
  385. popq %r13
  386. cfi_adjust_cfa_offset(-8)
  387. cfi_restore(%r13)
  388. popq %r12
  389. cfi_adjust_cfa_offset(-8)
  390. cfi_restore(%r12)
  391. retq
  392. cfi_adjust_cfa_offset(32)
  393. 1: cmpq $-ETIMEDOUT, %rax
  394. jne 2b
  395. 6: movl $ETIMEDOUT, %eax
  396. jmp 8b
  397. cfi_endproc
  398. .size __lll_timedwait_tid,.-__lll_timedwait_tid
  399. #endif