pthread_cond_wait.S 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /* Copyright (C) 2002-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 <lowlevellock.h>
  18. #include <lowlevelcond.h>
  19. #include <tcb-offsets.h>
  20. #include <pthread-pi-defines.h>
  21. #include <bits/kernel-features.h>
  22. .text
  23. /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
  24. .globl __pthread_cond_wait
  25. .type __pthread_cond_wait, @function
  26. .hidden __pthread_cond_wait
  27. .align 16
  28. __pthread_cond_wait:
  29. .LSTARTCODE:
  30. cfi_startproc
  31. #define FRAME_SIZE 32
  32. leaq -FRAME_SIZE(%rsp), %rsp
  33. cfi_adjust_cfa_offset(FRAME_SIZE)
  34. /* Stack frame:
  35. rsp + 32
  36. +--------------------------+
  37. rsp + 24 | old wake_seq value |
  38. +--------------------------+
  39. rsp + 16 | mutex pointer |
  40. +--------------------------+
  41. rsp + 8 | condvar pointer |
  42. +--------------------------+
  43. rsp + 4 | old broadcast_seq value |
  44. +--------------------------+
  45. rsp + 0 | old cancellation mode |
  46. +--------------------------+
  47. */
  48. cmpq $-1, dep_mutex(%rdi)
  49. /* Prepare structure passed to cancellation handler. */
  50. movq %rdi, 8(%rsp)
  51. movq %rsi, 16(%rsp)
  52. je 15f
  53. movq %rsi, dep_mutex(%rdi)
  54. /* Get internal lock. */
  55. 15: movl $1, %esi
  56. xorl %eax, %eax
  57. LOCK
  58. #if cond_lock == 0
  59. cmpxchgl %esi, (%rdi)
  60. #else
  61. cmpxchgl %esi, cond_lock(%rdi)
  62. #endif
  63. jne 1f
  64. /* Unlock the mutex. */
  65. 2: movq 16(%rsp), %rdi
  66. xorl %esi, %esi
  67. callq __pthread_mutex_unlock_usercnt
  68. testl %eax, %eax
  69. jne 12f
  70. movq 8(%rsp), %rdi
  71. incq total_seq(%rdi)
  72. incl cond_futex(%rdi)
  73. addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
  74. /* Get and store current wakeup_seq value. */
  75. movq 8(%rsp), %rdi
  76. movq wakeup_seq(%rdi), %r9
  77. movl broadcast_seq(%rdi), %edx
  78. movq %r9, 24(%rsp)
  79. movl %edx, 4(%rsp)
  80. /* Unlock. */
  81. 8: movl cond_futex(%rdi), %edx
  82. LOCK
  83. #if cond_lock == 0
  84. decl (%rdi)
  85. #else
  86. decl cond_lock(%rdi)
  87. #endif
  88. jne 3f
  89. .LcleanupSTART:
  90. 4: callq __pthread_enable_asynccancel
  91. movl %eax, (%rsp)
  92. xorq %r10, %r10
  93. cmpq $-1, dep_mutex(%rdi)
  94. leaq cond_futex(%rdi), %rdi
  95. movl $FUTEX_WAIT, %esi
  96. je 60f
  97. movq dep_mutex-cond_futex(%rdi), %r8
  98. /* Requeue to a non-robust PI mutex if the PI bit is set and
  99. the robust bit is not set. */
  100. movl MUTEX_KIND(%r8), %eax
  101. andl $(ROBUST_BIT|PI_BIT), %eax
  102. cmpl $PI_BIT, %eax
  103. jne 61f
  104. movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
  105. movl $SYS_futex, %eax
  106. syscall
  107. movl $1, %r8d
  108. #ifdef __ASSUME_REQUEUE_PI
  109. jmp 62f
  110. #else
  111. cmpq $-4095, %rax
  112. jnae 62f
  113. # ifndef __ASSUME_PRIVATE_FUTEX
  114. movl $FUTEX_WAIT, %esi
  115. # endif
  116. #endif
  117. 61:
  118. #ifdef __ASSUME_PRIVATE_FUTEX
  119. movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
  120. #else
  121. orl %fs:PRIVATE_FUTEX, %esi
  122. #endif
  123. 60: xorl %r8d, %r8d
  124. movl $SYS_futex, %eax
  125. syscall
  126. 62: movl (%rsp), %edi
  127. callq __pthread_disable_asynccancel
  128. .LcleanupEND:
  129. /* Lock. */
  130. movq 8(%rsp), %rdi
  131. movl $1, %esi
  132. xorl %eax, %eax
  133. LOCK
  134. #if cond_lock == 0
  135. cmpxchgl %esi, (%rdi)
  136. #else
  137. cmpxchgl %esi, cond_lock(%rdi)
  138. #endif
  139. jnz 5f
  140. 6: movl broadcast_seq(%rdi), %edx
  141. movq woken_seq(%rdi), %rax
  142. movq wakeup_seq(%rdi), %r9
  143. cmpl 4(%rsp), %edx
  144. jne 16f
  145. cmpq 24(%rsp), %r9
  146. jbe 8b
  147. cmpq %rax, %r9
  148. jna 8b
  149. incq woken_seq(%rdi)
  150. /* Unlock */
  151. 16: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
  152. /* Wake up a thread which wants to destroy the condvar object. */
  153. cmpq $0xffffffffffffffff, total_seq(%rdi)
  154. jne 17f
  155. movl cond_nwaiters(%rdi), %eax
  156. andl $~((1 << nwaiters_shift) - 1), %eax
  157. jne 17f
  158. addq $cond_nwaiters, %rdi
  159. cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
  160. movl $1, %edx
  161. #ifdef __ASSUME_PRIVATE_FUTEX
  162. movl $FUTEX_WAKE, %eax
  163. movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
  164. cmove %eax, %esi
  165. #else
  166. movl $0, %eax
  167. movl %fs:PRIVATE_FUTEX, %esi
  168. cmove %eax, %esi
  169. orl $FUTEX_WAKE, %esi
  170. #endif
  171. movl $SYS_futex, %eax
  172. syscall
  173. subq $cond_nwaiters, %rdi
  174. 17: LOCK
  175. #if cond_lock == 0
  176. decl (%rdi)
  177. #else
  178. decl cond_lock(%rdi)
  179. #endif
  180. jne 10f
  181. /* If requeue_pi is used the kernel performs the locking of the
  182. mutex. */
  183. 11: movq 16(%rsp), %rdi
  184. testl %r8d, %r8d
  185. jnz 18f
  186. callq __pthread_mutex_cond_lock
  187. 14: leaq FRAME_SIZE(%rsp), %rsp
  188. cfi_adjust_cfa_offset(-FRAME_SIZE)
  189. /* We return the result of the mutex_lock operation. */
  190. retq
  191. cfi_adjust_cfa_offset(FRAME_SIZE)
  192. 18: callq __pthread_mutex_cond_lock_adjust
  193. xorl %eax, %eax
  194. jmp 14b
  195. /* Initial locking failed. */
  196. 1:
  197. #if cond_lock != 0
  198. addq $cond_lock, %rdi
  199. #endif
  200. cmpq $-1, dep_mutex-cond_lock(%rdi)
  201. movl $LLL_PRIVATE, %eax
  202. movl $LLL_SHARED, %esi
  203. cmovne %eax, %esi
  204. callq __lll_lock_wait
  205. jmp 2b
  206. /* Unlock in loop requires wakeup. */
  207. 3:
  208. #if cond_lock != 0
  209. addq $cond_lock, %rdi
  210. #endif
  211. cmpq $-1, dep_mutex-cond_lock(%rdi)
  212. movl $LLL_PRIVATE, %eax
  213. movl $LLL_SHARED, %esi
  214. cmovne %eax, %esi
  215. /* The call preserves %rdx. */
  216. callq __lll_unlock_wake
  217. #if cond_lock != 0
  218. subq $cond_lock, %rdi
  219. #endif
  220. jmp 4b
  221. /* Locking in loop failed. */
  222. 5:
  223. #if cond_lock != 0
  224. addq $cond_lock, %rdi
  225. #endif
  226. cmpq $-1, dep_mutex-cond_lock(%rdi)
  227. movl $LLL_PRIVATE, %eax
  228. movl $LLL_SHARED, %esi
  229. cmovne %eax, %esi
  230. callq __lll_lock_wait
  231. #if cond_lock != 0
  232. subq $cond_lock, %rdi
  233. #endif
  234. jmp 6b
  235. /* Unlock after loop requires wakeup. */
  236. 10:
  237. #if cond_lock != 0
  238. addq $cond_lock, %rdi
  239. #endif
  240. cmpq $-1, dep_mutex-cond_lock(%rdi)
  241. movl $LLL_PRIVATE, %eax
  242. movl $LLL_SHARED, %esi
  243. cmovne %eax, %esi
  244. callq __lll_unlock_wake
  245. jmp 11b
  246. /* The initial unlocking of the mutex failed. */
  247. 12: movq %rax, %r10
  248. movq 8(%rsp), %rdi
  249. LOCK
  250. #if cond_lock == 0
  251. decl (%rdi)
  252. #else
  253. decl cond_lock(%rdi)
  254. #endif
  255. je 13f
  256. #if cond_lock != 0
  257. addq $cond_lock, %rdi
  258. #endif
  259. cmpq $-1, dep_mutex-cond_lock(%rdi)
  260. movl $LLL_PRIVATE, %eax
  261. movl $LLL_SHARED, %esi
  262. cmovne %eax, %esi
  263. callq __lll_unlock_wake
  264. 13: movq %r10, %rax
  265. jmp 14b
  266. .size __pthread_cond_wait, .-__pthread_cond_wait
  267. weak_alias(__pthread_cond_wait, pthread_cond_wait)
  268. .align 16
  269. .type __condvar_cleanup1, @function
  270. .globl __condvar_cleanup1
  271. .hidden __condvar_cleanup1
  272. __condvar_cleanup1:
  273. /* Stack frame:
  274. rsp + 32
  275. +--------------------------+
  276. rsp + 24 | unused |
  277. +--------------------------+
  278. rsp + 16 | mutex pointer |
  279. +--------------------------+
  280. rsp + 8 | condvar pointer |
  281. +--------------------------+
  282. rsp + 4 | old broadcast_seq value |
  283. +--------------------------+
  284. rsp + 0 | old cancellation mode |
  285. +--------------------------+
  286. */
  287. movq %rax, 24(%rsp)
  288. /* Get internal lock. */
  289. movq 8(%rsp), %rdi
  290. movl $1, %esi
  291. xorl %eax, %eax
  292. LOCK
  293. #if cond_lock == 0
  294. cmpxchgl %esi, (%rdi)
  295. #else
  296. cmpxchgl %esi, cond_lock(%rdi)
  297. #endif
  298. jz 1f
  299. #if cond_lock != 0
  300. addq $cond_lock, %rdi
  301. #endif
  302. cmpq $-1, dep_mutex-cond_lock(%rdi)
  303. movl $LLL_PRIVATE, %eax
  304. movl $LLL_SHARED, %esi
  305. cmovne %eax, %esi
  306. callq __lll_lock_wait
  307. #if cond_lock != 0
  308. subq $cond_lock, %rdi
  309. #endif
  310. 1: movl broadcast_seq(%rdi), %edx
  311. cmpl 4(%rsp), %edx
  312. jne 3f
  313. /* We increment the wakeup_seq counter only if it is lower than
  314. total_seq. If this is not the case the thread was woken and
  315. then canceled. In this case we ignore the signal. */
  316. movq total_seq(%rdi), %rax
  317. cmpq wakeup_seq(%rdi), %rax
  318. jbe 6f
  319. incq wakeup_seq(%rdi)
  320. incl cond_futex(%rdi)
  321. 6: incq woken_seq(%rdi)
  322. 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
  323. /* Wake up a thread which wants to destroy the condvar object. */
  324. xorl %ecx, %ecx
  325. cmpq $0xffffffffffffffff, total_seq(%rdi)
  326. jne 4f
  327. movl cond_nwaiters(%rdi), %eax
  328. andl $~((1 << nwaiters_shift) - 1), %eax
  329. jne 4f
  330. cmpq $-1, dep_mutex(%rdi)
  331. leaq cond_nwaiters(%rdi), %rdi
  332. movl $1, %edx
  333. #ifdef __ASSUME_PRIVATE_FUTEX
  334. movl $FUTEX_WAKE, %eax
  335. movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
  336. cmove %eax, %esi
  337. #else
  338. movl $0, %eax
  339. movl %fs:PRIVATE_FUTEX, %esi
  340. cmove %eax, %esi
  341. orl $FUTEX_WAKE, %esi
  342. #endif
  343. movl $SYS_futex, %eax
  344. syscall
  345. subq $cond_nwaiters, %rdi
  346. movl $1, %ecx
  347. 4: LOCK
  348. #if cond_lock == 0
  349. decl (%rdi)
  350. #else
  351. decl cond_lock(%rdi)
  352. #endif
  353. je 2f
  354. #if cond_lock != 0
  355. addq $cond_lock, %rdi
  356. #endif
  357. cmpq $-1, dep_mutex-cond_lock(%rdi)
  358. movl $LLL_PRIVATE, %eax
  359. movl $LLL_SHARED, %esi
  360. cmovne %eax, %esi
  361. /* The call preserves %rcx. */
  362. callq __lll_unlock_wake
  363. /* Wake up all waiters to make sure no signal gets lost. */
  364. 2: testl %ecx, %ecx
  365. jnz 5f
  366. addq $cond_futex, %rdi
  367. cmpq $-1, dep_mutex-cond_futex(%rdi)
  368. movl $0x7fffffff, %edx
  369. #ifdef __ASSUME_PRIVATE_FUTEX
  370. movl $FUTEX_WAKE, %eax
  371. movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
  372. cmove %eax, %esi
  373. #else
  374. movl $0, %eax
  375. movl %fs:PRIVATE_FUTEX, %esi
  376. cmove %eax, %esi
  377. orl $FUTEX_WAKE, %esi
  378. #endif
  379. movl $SYS_futex, %eax
  380. syscall
  381. 5: movq 16(%rsp), %rdi
  382. callq __pthread_mutex_cond_lock
  383. movq 24(%rsp), %rdi
  384. .LcallUR:
  385. call _Unwind_Resume@PLT
  386. hlt
  387. .LENDCODE:
  388. cfi_endproc
  389. .size __condvar_cleanup1, .-__condvar_cleanup1
  390. .section .gcc_except_table,"a",@progbits
  391. .LexceptSTART:
  392. .byte DW_EH_PE_omit # @LPStart format
  393. .byte DW_EH_PE_omit # @TType format
  394. .byte DW_EH_PE_uleb128 # call-site format
  395. .uleb128 .Lcstend-.Lcstbegin
  396. .Lcstbegin:
  397. .uleb128 .LcleanupSTART-.LSTARTCODE
  398. .uleb128 .LcleanupEND-.LcleanupSTART
  399. .uleb128 __condvar_cleanup1-.LSTARTCODE
  400. .uleb128 0
  401. .uleb128 .LcallUR-.LSTARTCODE
  402. .uleb128 .LENDCODE-.LcallUR
  403. .uleb128 0
  404. .uleb128 0
  405. .Lcstend:
  406. #ifdef SHARED
  407. .hidden DW.ref.__gcc_personality_v0
  408. .weak DW.ref.__gcc_personality_v0
  409. .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
  410. .align 8
  411. .type DW.ref.__gcc_personality_v0, @object
  412. .size DW.ref.__gcc_personality_v0, 8
  413. DW.ref.__gcc_personality_v0:
  414. .quad __gcc_personality_v0
  415. #endif