pthread_cond_wait.S 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /* Copyright (C) 2002-2004,2006-2007,2009,2010 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 <lowlevellock.h>
  17. #include <lowlevelcond.h>
  18. #include <tcb-offsets.h>
  19. #include <pthread-errnos.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. .protected __pthread_cond_wait
  27. .align 16
  28. __pthread_cond_wait:
  29. .LSTARTCODE:
  30. cfi_startproc
  31. #ifdef SHARED
  32. cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
  33. DW.ref.__gcc_personality_v0)
  34. cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
  35. #else
  36. cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
  37. cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
  38. #endif
  39. pushl %ebp
  40. cfi_adjust_cfa_offset(4)
  41. cfi_rel_offset(%ebp, 0)
  42. pushl %edi
  43. cfi_adjust_cfa_offset(4)
  44. cfi_rel_offset(%edi, 0)
  45. pushl %esi
  46. cfi_adjust_cfa_offset(4)
  47. cfi_rel_offset(%esi, 0)
  48. pushl %ebx
  49. cfi_adjust_cfa_offset(4)
  50. cfi_rel_offset(%ebx, 0)
  51. xorl %esi, %esi
  52. movl 20(%esp), %ebx
  53. /* Get internal lock. */
  54. movl $1, %edx
  55. xorl %eax, %eax
  56. LOCK
  57. #if cond_lock == 0
  58. cmpxchgl %edx, (%ebx)
  59. #else
  60. cmpxchgl %edx, cond_lock(%ebx)
  61. #endif
  62. jnz 1f
  63. /* Store the reference to the mutex. If there is already a
  64. different value in there this is a bad user bug. */
  65. 2: cmpl $-1, dep_mutex(%ebx)
  66. movl 24(%esp), %eax
  67. je 15f
  68. movl %eax, dep_mutex(%ebx)
  69. /* Unlock the mutex. */
  70. 15: xorl %edx, %edx
  71. call __pthread_mutex_unlock_usercnt
  72. testl %eax, %eax
  73. jne 12f
  74. addl $1, total_seq(%ebx)
  75. adcl $0, total_seq+4(%ebx)
  76. addl $1, cond_futex(%ebx)
  77. addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
  78. #define FRAME_SIZE 20
  79. subl $FRAME_SIZE, %esp
  80. cfi_adjust_cfa_offset(FRAME_SIZE)
  81. cfi_remember_state
  82. /* Get and store current wakeup_seq value. */
  83. movl wakeup_seq(%ebx), %edi
  84. movl wakeup_seq+4(%ebx), %edx
  85. movl broadcast_seq(%ebx), %eax
  86. movl %edi, 4(%esp)
  87. movl %edx, 8(%esp)
  88. movl %eax, 12(%esp)
  89. /* Reset the pi-requeued flag. */
  90. 8: movl $0, 16(%esp)
  91. movl cond_futex(%ebx), %ebp
  92. /* Unlock. */
  93. LOCK
  94. #if cond_lock == 0
  95. subl $1, (%ebx)
  96. #else
  97. subl $1, cond_lock(%ebx)
  98. #endif
  99. jne 3f
  100. .LcleanupSTART:
  101. 4: call __pthread_enable_asynccancel
  102. movl %eax, (%esp)
  103. xorl %ecx, %ecx
  104. cmpl $-1, dep_mutex(%ebx)
  105. sete %cl
  106. je 18f
  107. movl dep_mutex(%ebx), %edi
  108. /* Requeue to a non-robust PI mutex if the PI bit is set and
  109. the robust bit is not set. */
  110. movl MUTEX_KIND(%edi), %eax
  111. andl $(ROBUST_BIT|PI_BIT), %eax
  112. cmpl $PI_BIT, %eax
  113. jne 18f
  114. movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
  115. movl %ebp, %edx
  116. xorl %esi, %esi
  117. addl $cond_futex, %ebx
  118. movl $SYS_futex, %eax
  119. ENTER_KERNEL
  120. subl $cond_futex, %ebx
  121. /* Set the pi-requeued flag only if the kernel has returned 0. The
  122. kernel does not hold the mutex on error. */
  123. cmpl $0, %eax
  124. sete 16(%esp)
  125. je 19f
  126. /* Normal and PI futexes dont mix. Use normal futex functions only
  127. if the kernel does not support the PI futex functions. */
  128. cmpl $-ENOSYS, %eax
  129. jne 19f
  130. xorl %ecx, %ecx
  131. 18: subl $1, %ecx
  132. #ifdef __ASSUME_PRIVATE_FUTEX
  133. andl $FUTEX_PRIVATE_FLAG, %ecx
  134. #else
  135. andl %gs:PRIVATE_FUTEX, %ecx
  136. #endif
  137. #if FUTEX_WAIT != 0
  138. addl $FUTEX_WAIT, %ecx
  139. #endif
  140. movl %ebp, %edx
  141. addl $cond_futex, %ebx
  142. .Ladd_cond_futex:
  143. movl $SYS_futex, %eax
  144. ENTER_KERNEL
  145. subl $cond_futex, %ebx
  146. .Lsub_cond_futex:
  147. 19: movl (%esp), %eax
  148. call __pthread_disable_asynccancel
  149. .LcleanupEND:
  150. /* Lock. */
  151. movl $1, %edx
  152. xorl %eax, %eax
  153. LOCK
  154. #if cond_lock == 0
  155. cmpxchgl %edx, (%ebx)
  156. #else
  157. cmpxchgl %edx, cond_lock(%ebx)
  158. #endif
  159. jnz 5f
  160. 6: movl broadcast_seq(%ebx), %eax
  161. cmpl 12(%esp), %eax
  162. jne 16f
  163. movl woken_seq(%ebx), %eax
  164. movl woken_seq+4(%ebx), %ecx
  165. movl wakeup_seq(%ebx), %edi
  166. movl wakeup_seq+4(%ebx), %edx
  167. cmpl 8(%esp), %edx
  168. jne 7f
  169. cmpl 4(%esp), %edi
  170. je 8b
  171. 7: cmpl %ecx, %edx
  172. jne 9f
  173. cmp %eax, %edi
  174. je 8b
  175. 9: addl $1, woken_seq(%ebx)
  176. adcl $0, woken_seq+4(%ebx)
  177. /* Unlock */
  178. 16: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
  179. /* Wake up a thread which wants to destroy the condvar object. */
  180. movl total_seq(%ebx), %eax
  181. andl total_seq+4(%ebx), %eax
  182. cmpl $0xffffffff, %eax
  183. jne 17f
  184. movl cond_nwaiters(%ebx), %eax
  185. andl $~((1 << nwaiters_shift) - 1), %eax
  186. jne 17f
  187. addl $cond_nwaiters, %ebx
  188. movl $SYS_futex, %eax
  189. #if FUTEX_PRIVATE_FLAG > 255
  190. xorl %ecx, %ecx
  191. #endif
  192. cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
  193. sete %cl
  194. subl $1, %ecx
  195. #ifdef __ASSUME_PRIVATE_FUTEX
  196. andl $FUTEX_PRIVATE_FLAG, %ecx
  197. #else
  198. andl %gs:PRIVATE_FUTEX, %ecx
  199. #endif
  200. addl $FUTEX_WAKE, %ecx
  201. movl $1, %edx
  202. ENTER_KERNEL
  203. subl $cond_nwaiters, %ebx
  204. 17: LOCK
  205. #if cond_lock == 0
  206. subl $1, (%ebx)
  207. #else
  208. subl $1, cond_lock(%ebx)
  209. #endif
  210. jne 10f
  211. /* With requeue_pi, the mutex lock is held in the kernel. */
  212. 11: movl 24+FRAME_SIZE(%esp), %eax
  213. movl 16(%esp), %ecx
  214. testl %ecx, %ecx
  215. jnz 21f
  216. call __pthread_mutex_cond_lock
  217. 20: addl $FRAME_SIZE, %esp
  218. cfi_adjust_cfa_offset(-FRAME_SIZE);
  219. 14: popl %ebx
  220. cfi_adjust_cfa_offset(-4)
  221. cfi_restore(%ebx)
  222. popl %esi
  223. cfi_adjust_cfa_offset(-4)
  224. cfi_restore(%esi)
  225. popl %edi
  226. cfi_adjust_cfa_offset(-4)
  227. cfi_restore(%edi)
  228. popl %ebp
  229. cfi_adjust_cfa_offset(-4)
  230. cfi_restore(%ebp)
  231. /* We return the result of the mutex_lock operation. */
  232. ret
  233. cfi_restore_state
  234. 21: call __pthread_mutex_cond_lock_adjust
  235. xorl %eax, %eax
  236. jmp 20b
  237. cfi_adjust_cfa_offset(-FRAME_SIZE);
  238. /* Initial locking failed. */
  239. 1:
  240. #if cond_lock == 0
  241. movl %ebx, %edx
  242. #else
  243. leal cond_lock(%ebx), %edx
  244. #endif
  245. #if (LLL_SHARED-LLL_PRIVATE) > 255
  246. xorl %ecx, %ecx
  247. #endif
  248. cmpl $-1, dep_mutex(%ebx)
  249. setne %cl
  250. subl $1, %ecx
  251. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  252. #if LLL_PRIVATE != 0
  253. addl $LLL_PRIVATE, %ecx
  254. #endif
  255. call __lll_lock_wait
  256. jmp 2b
  257. /* The initial unlocking of the mutex failed. */
  258. 12:
  259. LOCK
  260. #if cond_lock == 0
  261. subl $1, (%ebx)
  262. #else
  263. subl $1, cond_lock(%ebx)
  264. #endif
  265. jne 14b
  266. movl %eax, %esi
  267. #if cond_lock == 0
  268. movl %ebx, %eax
  269. #else
  270. leal cond_lock(%ebx), %eax
  271. #endif
  272. #if (LLL_SHARED-LLL_PRIVATE) > 255
  273. xorl %ecx, %ecx
  274. #endif
  275. cmpl $-1, dep_mutex(%ebx)
  276. setne %cl
  277. subl $1, %ecx
  278. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  279. #if LLL_PRIVATE != 0
  280. addl $LLL_PRIVATE, %ecx
  281. #endif
  282. call __lll_unlock_wake
  283. movl %esi, %eax
  284. jmp 14b
  285. cfi_adjust_cfa_offset(FRAME_SIZE)
  286. /* Unlock in loop requires wakeup. */
  287. 3:
  288. #if cond_lock == 0
  289. movl %ebx, %eax
  290. #else
  291. leal cond_lock(%ebx), %eax
  292. #endif
  293. #if (LLL_SHARED-LLL_PRIVATE) > 255
  294. xorl %ecx, %ecx
  295. #endif
  296. cmpl $-1, dep_mutex(%ebx)
  297. setne %cl
  298. subl $1, %ecx
  299. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  300. #if LLL_PRIVATE != 0
  301. addl $LLL_PRIVATE, %ecx
  302. #endif
  303. call __lll_unlock_wake
  304. jmp 4b
  305. /* Locking in loop failed. */
  306. 5:
  307. #if cond_lock == 0
  308. movl %ebx, %edx
  309. #else
  310. leal cond_lock(%ebx), %edx
  311. #endif
  312. #if (LLL_SHARED-LLL_PRIVATE) > 255
  313. xorl %ecx, %ecx
  314. #endif
  315. cmpl $-1, dep_mutex(%ebx)
  316. setne %cl
  317. subl $1, %ecx
  318. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  319. #if LLL_PRIVATE != 0
  320. addl $LLL_PRIVATE, %ecx
  321. #endif
  322. call __lll_lock_wait
  323. jmp 6b
  324. /* Unlock after loop requires wakeup. */
  325. 10:
  326. #if cond_lock == 0
  327. movl %ebx, %eax
  328. #else
  329. leal cond_lock(%ebx), %eax
  330. #endif
  331. #if (LLL_SHARED-LLL_PRIVATE) > 255
  332. xorl %ecx, %ecx
  333. #endif
  334. cmpl $-1, dep_mutex(%ebx)
  335. setne %cl
  336. subl $1, %ecx
  337. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  338. #if LLL_PRIVATE != 0
  339. addl $LLL_PRIVATE, %ecx
  340. #endif
  341. call __lll_unlock_wake
  342. jmp 11b
  343. .size __pthread_cond_wait, .-__pthread_cond_wait
  344. weak_alias(__pthread_cond_wait, pthread_cond_wait)
  345. .type __condvar_w_cleanup2, @function
  346. __condvar_w_cleanup2:
  347. subl $cond_futex, %ebx
  348. .size __condvar_w_cleanup2, .-__condvar_w_cleanup2
  349. .LSbl4:
  350. .type __condvar_w_cleanup, @function
  351. __condvar_w_cleanup:
  352. movl %eax, %esi
  353. /* Get internal lock. */
  354. movl $1, %edx
  355. xorl %eax, %eax
  356. LOCK
  357. #if cond_lock == 0
  358. cmpxchgl %edx, (%ebx)
  359. #else
  360. cmpxchgl %edx, cond_lock(%ebx)
  361. #endif
  362. jz 1f
  363. #if cond_lock == 0
  364. movl %ebx, %edx
  365. #else
  366. leal cond_lock(%ebx), %edx
  367. #endif
  368. #if (LLL_SHARED-LLL_PRIVATE) > 255
  369. xorl %ecx, %ecx
  370. #endif
  371. cmpl $-1, dep_mutex(%ebx)
  372. setne %cl
  373. subl $1, %ecx
  374. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  375. #if LLL_PRIVATE != 0
  376. addl $LLL_PRIVATE, %ecx
  377. #endif
  378. call __lll_lock_wait
  379. 1: movl broadcast_seq(%ebx), %eax
  380. cmpl 12(%esp), %eax
  381. jne 3f
  382. /* We increment the wakeup_seq counter only if it is lower than
  383. total_seq. If this is not the case the thread was woken and
  384. then canceled. In this case we ignore the signal. */
  385. movl total_seq(%ebx), %eax
  386. movl total_seq+4(%ebx), %edi
  387. cmpl wakeup_seq+4(%ebx), %edi
  388. jb 6f
  389. ja 7f
  390. cmpl wakeup_seq(%ebx), %eax
  391. jbe 7f
  392. 6: addl $1, wakeup_seq(%ebx)
  393. adcl $0, wakeup_seq+4(%ebx)
  394. addl $1, cond_futex(%ebx)
  395. 7: addl $1, woken_seq(%ebx)
  396. adcl $0, woken_seq+4(%ebx)
  397. 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
  398. /* Wake up a thread which wants to destroy the condvar object. */
  399. xorl %edi, %edi
  400. movl total_seq(%ebx), %eax
  401. andl total_seq+4(%ebx), %eax
  402. cmpl $0xffffffff, %eax
  403. jne 4f
  404. movl cond_nwaiters(%ebx), %eax
  405. andl $~((1 << nwaiters_shift) - 1), %eax
  406. jne 4f
  407. addl $cond_nwaiters, %ebx
  408. movl $SYS_futex, %eax
  409. #if FUTEX_PRIVATE_FLAG > 255
  410. xorl %ecx, %ecx
  411. #endif
  412. cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
  413. sete %cl
  414. subl $1, %ecx
  415. #ifdef __ASSUME_PRIVATE_FUTEX
  416. andl $FUTEX_PRIVATE_FLAG, %ecx
  417. #else
  418. andl %gs:PRIVATE_FUTEX, %ecx
  419. #endif
  420. addl $FUTEX_WAKE, %ecx
  421. movl $1, %edx
  422. ENTER_KERNEL
  423. subl $cond_nwaiters, %ebx
  424. movl $1, %edi
  425. 4: LOCK
  426. #if cond_lock == 0
  427. subl $1, (%ebx)
  428. #else
  429. subl $1, cond_lock(%ebx)
  430. #endif
  431. je 2f
  432. #if cond_lock == 0
  433. movl %ebx, %eax
  434. #else
  435. leal cond_lock(%ebx), %eax
  436. #endif
  437. #if (LLL_SHARED-LLL_PRIVATE) > 255
  438. xorl %ecx, %ecx
  439. #endif
  440. cmpl $-1, dep_mutex(%ebx)
  441. setne %cl
  442. subl $1, %ecx
  443. andl $(LLL_SHARED-LLL_PRIVATE), %ecx
  444. #if LLL_PRIVATE != 0
  445. addl $LLL_PRIVATE, %ecx
  446. #endif
  447. call __lll_unlock_wake
  448. /* Wake up all waiters to make sure no signal gets lost. */
  449. 2: testl %edi, %edi
  450. jnz 5f
  451. addl $cond_futex, %ebx
  452. #if FUTEX_PRIVATE_FLAG > 255
  453. xorl %ecx, %ecx
  454. #endif
  455. cmpl $-1, dep_mutex-cond_futex(%ebx)
  456. sete %cl
  457. subl $1, %ecx
  458. #ifdef __ASSUME_PRIVATE_FUTEX
  459. andl $FUTEX_PRIVATE_FLAG, %ecx
  460. #else
  461. andl %gs:PRIVATE_FUTEX, %ecx
  462. #endif
  463. addl $FUTEX_WAKE, %ecx
  464. movl $SYS_futex, %eax
  465. movl $0x7fffffff, %edx
  466. ENTER_KERNEL
  467. 5: movl 24+FRAME_SIZE(%esp), %eax
  468. call __pthread_mutex_cond_lock
  469. movl %esi, (%esp)
  470. .LcallUR:
  471. #ifdef __PIC__
  472. call __i686.get_pc_thunk.bx
  473. addl $_GLOBAL_OFFSET_TABLE_, %ebx
  474. #endif
  475. call _Unwind_Resume@PLT
  476. hlt
  477. .LENDCODE:
  478. cfi_endproc
  479. .size __condvar_w_cleanup, .-__condvar_w_cleanup
  480. .section .gcc_except_table,"a",@progbits
  481. .LexceptSTART:
  482. .byte DW_EH_PE_omit # @LPStart format (omit)
  483. .byte DW_EH_PE_omit # @TType format (omit)
  484. .byte DW_EH_PE_sdata4 # call-site format
  485. # DW_EH_PE_sdata4
  486. .uleb128 .Lcstend-.Lcstbegin
  487. .Lcstbegin:
  488. .long .LcleanupSTART-.LSTARTCODE
  489. .long .Ladd_cond_futex-.LcleanupSTART
  490. .long __condvar_w_cleanup-.LSTARTCODE
  491. .uleb128 0
  492. .long .Ladd_cond_futex-.LSTARTCODE
  493. .long .Lsub_cond_futex-.Ladd_cond_futex
  494. .long __condvar_w_cleanup2-.LSTARTCODE
  495. .uleb128 0
  496. .long .Lsub_cond_futex-.LSTARTCODE
  497. .long .LcleanupEND-.Lsub_cond_futex
  498. .long __condvar_w_cleanup-.LSTARTCODE
  499. .uleb128 0
  500. .long .LcallUR-.LSTARTCODE
  501. .long .LENDCODE-.LcallUR
  502. .long 0
  503. .uleb128 0
  504. .Lcstend:
  505. #ifdef __PIC__
  506. .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
  507. .globl __i686.get_pc_thunk.bx
  508. .hidden __i686.get_pc_thunk.bx
  509. .type __i686.get_pc_thunk.bx,@function
  510. __i686.get_pc_thunk.bx:
  511. movl (%esp), %ebx;
  512. ret
  513. .size __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx
  514. #endif
  515. #ifdef SHARED
  516. .hidden DW.ref.__gcc_personality_v0
  517. .weak DW.ref.__gcc_personality_v0
  518. .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
  519. .align 4
  520. .type DW.ref.__gcc_personality_v0, @object
  521. .size DW.ref.__gcc_personality_v0, 4
  522. DW.ref.__gcc_personality_v0:
  523. .long __gcc_personality_v0
  524. #endif