lowlevellock.S 9.2 KB

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