1#include <sch/sched.h>
2#include <sync/condvar.h>
3#include <thread/thread.h>
4#include <thread/workqueue.h>
5
6static void condvar_prepare_wait(struct condvar *cv) {
7 thread_wait_prepare_one(header: &cv->waiters, object: cv, type: THREAD_WAIT_UNINTERRUPTIBLE,
8 reason: THREAD_BLOCK_REASON_MANUAL);
9}
10
11static enum wake_reason
12condvar_finish_wait(struct spinlock *lock, enum irql irql, enum irql *out,
13 bool timed, time_ms_t timeout_ms) TSA_NO_ANALYSIS {
14 enum irql sirql = irql_get();
15
16 spin_unlock(lock, irql);
17 struct thread_wait_result result =
18 timed ? thread_wait_complete_timeout(timeout_ms)
19 : thread_wait_complete();
20 enum wake_reason reason = result.reason == THREAD_WAKE_REASON_SLEEP_TIMEOUT
21 ? WAKE_REASON_TIMEOUT
22 : WAKE_REASON_SIGNAL;
23
24 *out = sirql == IRQL_HIGH_LEVEL ? spin_lock_high(lock) : spin_lock(lock);
25 return reason;
26}
27
28enum wake_reason condvar_wait(struct condvar *cv, struct spinlock *lock,
29 enum irql irql, enum irql *out) TSA_NO_ANALYSIS {
30 condvar_prepare_wait(cv);
31 return condvar_finish_wait(lock, irql, out, false, timeout_ms: 0);
32}
33
34void condvar_init(struct condvar *cv) {
35 thread_wait_header_init(header: &cv->waiters);
36}
37
38static void nop_callback(struct thread *unused) {
39 cc_ignore(unused);
40}
41
42struct thread *condvar_signal_callback(struct condvar *cv,
43 thread_action_callback tac) {
44 struct thread *t = thread_wait_header_satisfy(
45 hdr: &cv->waiters, reason: THREAD_WAKE_REASON_SLEEP_MANUAL, cb: tac);
46
47 if (!t)
48 tac(NULL);
49 return t;
50}
51
52struct thread *condvar_signal(struct condvar *cv) {
53 return condvar_signal_callback(cv, tac: nop_callback);
54}
55
56void condvar_broadcast_callback(struct condvar *cv,
57 thread_action_callback tac) {
58 thread_wait_header_satisfy_all(
59 hdr: &cv->waiters, reason: THREAD_WAKE_REASON_SLEEP_MANUAL, callback: tac, NULL, NULL);
60}
61
62void condvar_broadcast(struct condvar *cv) {
63 condvar_broadcast_callback(cv, tac: nop_callback);
64}
65
66enum wake_reason condvar_wait_timeout(struct condvar *cv, struct spinlock *lock,
67 time_ms_t timeout_ms, enum irql irql,
68 enum irql *out) TSA_NO_ANALYSIS {
69 condvar_prepare_wait(cv);
70 return condvar_finish_wait(lock, irql, out, true, timeout_ms);
71}
72