blob: 4845251c7586c9667cd33c38af3701910d65eaa8 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001Conditional Variable pseudocode.
2================================
3
4 int pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *mutex);
5 int pthread_cond_signal (pthread_cond_t *cv);
6 int pthread_cond_broadcast (pthread_cond_t *cv);
7
8struct pthread_cond_t {
9
10 unsigned int cond_lock;
11
12 internal mutex
13
14 uint64_t total_seq;
15
16 Total number of threads using the conditional variable.
17
18 uint64_t wakeup_seq;
19
20 sequence number for next wakeup.
21
22 uint64_t woken_seq;
23
24 sequence number of last woken thread.
25
26 uint32_t broadcast_seq;
27
28}
29
30
31struct cv_data {
32
33 pthread_cond_t *cv;
34
35 uint32_t bc_seq
36
37}
38
39
40
41cleanup_handler(cv_data)
42{
43 cv = cv_data->cv;
44 lll_lock(cv->lock);
45
46 if (cv_data->bc_seq == cv->broadcast_seq) {
47 ++cv->wakeup_seq;
48 ++cv->woken_seq;
49 }
50
51 /* make sure no signal gets lost. */
52 FUTEX_WAKE(cv->wakeup_seq, ALL);
53
54 lll_unlock(cv->lock);
55}
56
57
58cond_timedwait(cv, mutex, timeout):
59{
60 lll_lock(cv->lock);
61 mutex_unlock(mutex);
62
63 cleanup_push
64
65 ++cv->total_seq;
66 val = seq = cv->wakeup_seq;
67 cv_data.bc = cv->broadcast_seq;
68 cv_data.cv = cv;
69
70 while (1) {
71
72 lll_unlock(cv->lock);
73
74 enable_async(&cv_data);
75
76 ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
77
78 restore_async
79
80 lll_lock(cv->lock);
81
82 if (bc != cv->broadcast_seq)
83 goto bc_out;
84
85 val = cv->wakeup_seq;
86
87 if (val != seq && cv->woken_seq != val) {
88 ret = 0;
89 break;
90 }
91
92 if (ret == TIMEDOUT) {
93 ++cv->wakeup_seq;
94 break;
95 }
96 }
97
98 ++cv->woken_seq;
99
100 bc_out:
101 lll_unlock(cv->lock);
102
103 cleanup_pop
104
105 mutex_lock(mutex);
106
107 return ret;
108}
109
110cond_signal(cv)
111{
112 lll_lock(cv->lock);
113
114 if (cv->total_seq > cv->wakeup_seq) {
115 ++cv->wakeup_seq;
116 FUTEX_WAKE(cv->wakeup_seq, 1);
117 }
118
119 lll_unlock(cv->lock);
120}
121
122cond_broadcast(cv)
123{
124 lll_lock(cv->lock);
125
126 if (cv->total_seq > cv->wakeup_seq) {
127 cv->wakeup_seq = cv->total_seq;
128 cv->woken_seq = cv->total_seq;
129 ++cv->broadcast_seq;
130 FUTEX_WAKE(cv->wakeup_seq, ALL);
131 }
132
133 lll_unlock(cv->lock);
134}