DESIGN-condvar.txt 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. Conditional Variable pseudocode.
  2. ================================
  3. int pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *mutex);
  4. int pthread_cond_signal (pthread_cond_t *cv);
  5. int pthread_cond_broadcast (pthread_cond_t *cv);
  6. struct pthread_cond_t {
  7. unsigned int cond_lock;
  8. internal mutex
  9. uint64_t total_seq;
  10. Total number of threads using the conditional variable.
  11. uint64_t wakeup_seq;
  12. sequence number for next wakeup.
  13. uint64_t woken_seq;
  14. sequence number of last woken thread.
  15. uint32_t broadcast_seq;
  16. }
  17. struct cv_data {
  18. pthread_cond_t *cv;
  19. uint32_t bc_seq
  20. }
  21. cleanup_handler(cv_data)
  22. {
  23. cv = cv_data->cv;
  24. lll_lock(cv->lock);
  25. if (cv_data->bc_seq == cv->broadcast_seq) {
  26. ++cv->wakeup_seq;
  27. ++cv->woken_seq;
  28. }
  29. /* make sure no signal gets lost. */
  30. FUTEX_WAKE(cv->wakeup_seq, ALL);
  31. lll_unlock(cv->lock);
  32. }
  33. cond_timedwait(cv, mutex, timeout):
  34. {
  35. lll_lock(cv->lock);
  36. mutex_unlock(mutex);
  37. cleanup_push
  38. ++cv->total_seq;
  39. val = seq = cv->wakeup_seq;
  40. cv_data.bc = cv->broadcast_seq;
  41. cv_data.cv = cv;
  42. while (1) {
  43. lll_unlock(cv->lock);
  44. enable_async(&cv_data);
  45. ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
  46. restore_async
  47. lll_lock(cv->lock);
  48. if (bc != cv->broadcast_seq)
  49. goto bc_out;
  50. val = cv->wakeup_seq;
  51. if (val != seq && cv->woken_seq != val) {
  52. ret = 0;
  53. break;
  54. }
  55. if (ret == TIMEDOUT) {
  56. ++cv->wakeup_seq;
  57. break;
  58. }
  59. }
  60. ++cv->woken_seq;
  61. bc_out:
  62. lll_unlock(cv->lock);
  63. cleanup_pop
  64. mutex_lock(mutex);
  65. return ret;
  66. }
  67. cond_signal(cv)
  68. {
  69. lll_lock(cv->lock);
  70. if (cv->total_seq > cv->wakeup_seq) {
  71. ++cv->wakeup_seq;
  72. FUTEX_WAKE(cv->wakeup_seq, 1);
  73. }
  74. lll_unlock(cv->lock);
  75. }
  76. cond_broadcast(cv)
  77. {
  78. lll_lock(cv->lock);
  79. if (cv->total_seq > cv->wakeup_seq) {
  80. cv->wakeup_seq = cv->total_seq;
  81. cv->woken_seq = cv->total_seq;
  82. ++cv->broadcast_seq;
  83. FUTEX_WAKE(cv->wakeup_seq, ALL);
  84. }
  85. lll_unlock(cv->lock);
  86. }