pthread_barrier_wait.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #include "pthread_impl.h"
  2. static int pshared_barrier_wait(pthread_barrier_t *b)
  3. {
  4. int limit = (b->_b_limit & INT_MAX) + 1;
  5. int ret = 0;
  6. int v, w;
  7. if (limit==1) return PTHREAD_BARRIER_SERIAL_THREAD;
  8. while ((v=a_cas(&b->_b_lock, 0, limit)))
  9. __wait(&b->_b_lock, &b->_b_waiters, v, 0);
  10. /* Wait for <limit> threads to get to the barrier */
  11. if (++b->_b_count == limit) {
  12. a_store(&b->_b_count, 0);
  13. ret = PTHREAD_BARRIER_SERIAL_THREAD;
  14. if (b->_b_waiters2) __wake(&b->_b_count, -1, 0);
  15. } else {
  16. a_store(&b->_b_lock, 0);
  17. if (b->_b_waiters) __wake(&b->_b_lock, 1, 0);
  18. while ((v=b->_b_count)>0)
  19. __wait(&b->_b_count, &b->_b_waiters2, v, 0);
  20. }
  21. __vm_lock();
  22. /* Ensure all threads have a vm lock before proceeding */
  23. if (a_fetch_add(&b->_b_count, -1)==1-limit) {
  24. a_store(&b->_b_count, 0);
  25. if (b->_b_waiters2) __wake(&b->_b_count, -1, 0);
  26. } else {
  27. while ((v=b->_b_count))
  28. __wait(&b->_b_count, &b->_b_waiters2, v, 0);
  29. }
  30. /* Perform a recursive unlock suitable for self-sync'd destruction */
  31. do {
  32. v = b->_b_lock;
  33. w = b->_b_waiters;
  34. } while (a_cas(&b->_b_lock, v, v==INT_MIN+1 ? 0 : v-1) != v);
  35. /* Wake a thread waiting to reuse or destroy the barrier */
  36. if (v==INT_MIN+1 || (v==1 && w))
  37. __wake(&b->_b_lock, 1, 0);
  38. __vm_unlock();
  39. return ret;
  40. }
  41. struct instance
  42. {
  43. volatile int count;
  44. volatile int last;
  45. volatile int waiters;
  46. volatile int finished;
  47. };
  48. int pthread_barrier_wait(pthread_barrier_t *b)
  49. {
  50. int limit = b->_b_limit;
  51. struct instance *inst;
  52. /* Trivial case: count was set at 1 */
  53. if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD;
  54. /* Process-shared barriers require a separate, inefficient wait */
  55. if (limit < 0) return pshared_barrier_wait(b);
  56. /* Otherwise we need a lock on the barrier object */
  57. while (a_swap(&b->_b_lock, 1))
  58. __wait(&b->_b_lock, &b->_b_waiters, 1, 1);
  59. inst = b->_b_inst;
  60. /* First thread to enter the barrier becomes the "instance owner" */
  61. if (!inst) {
  62. struct instance new_inst = { 0 };
  63. int spins = 200;
  64. b->_b_inst = inst = &new_inst;
  65. a_store(&b->_b_lock, 0);
  66. if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
  67. while (spins-- && !inst->finished)
  68. a_spin();
  69. a_inc(&inst->finished);
  70. while (inst->finished == 1)
  71. __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|128,1,0) != -ENOSYS
  72. || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
  73. return PTHREAD_BARRIER_SERIAL_THREAD;
  74. }
  75. /* Last thread to enter the barrier wakes all non-instance-owners */
  76. if (++inst->count == limit) {
  77. b->_b_inst = 0;
  78. a_store(&b->_b_lock, 0);
  79. if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
  80. a_store(&inst->last, 1);
  81. if (inst->waiters)
  82. __wake(&inst->last, -1, 1);
  83. } else {
  84. a_store(&b->_b_lock, 0);
  85. if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
  86. __wait(&inst->last, &inst->waiters, 0, 1);
  87. }
  88. /* Last thread to exit the barrier wakes the instance owner */
  89. if (a_fetch_add(&inst->count,-1)==1 && a_fetch_add(&inst->finished,1))
  90. __wake(&inst->finished, 1, 1);
  91. return 0;
  92. }