1#include <sch/sched.h>
2#include <sync/condvar.h>
3#include <sync/semaphore.h>
4#include <sync/spinlock.h>
5#include <thread/thread_types.h>
6
7LOCK_CHK_CLASS_DEFINE_LOCAL(semaphore_irq);
8LOCK_CHK_CLASS_DEFINE_LOCAL(semaphore_disp);
9
10void semaphore_init(struct semaphore *s, int value, bool irq_disable) {
11 s->count = value;
12 s->irq_disable = irq_disable;
13 if (irq_disable) {
14 spinlock_init_chk(&s->lock, LOCK_CHK_CLASS(semaphore_irq),
15 LOCK_CHKD_FULL);
16 } else {
17 spinlock_init_chk(&s->lock, LOCK_CHK_CLASS(semaphore_disp),
18 LOCK_CHKD_FULL);
19 }
20 condvar_init(cv: &s->cv);
21}
22
23static enum irql
24semaphore_lock_internal(struct semaphore *sem) TSA_NO_ANALYSIS {
25 if (sem->irq_disable)
26 return spin_lock_high(&sem->lock);
27
28 return spin_lock(&sem->lock);
29}
30
31void semaphore_wait(struct semaphore *s) TSA_NO_ANALYSIS {
32 enum irql irql = semaphore_lock_internal(sem: s);
33
34 while (s->count == 0)
35 condvar_wait(cv: &s->cv, lock: &s->lock, irql, out: &irql);
36
37 s->count--;
38 spin_unlock(&s->lock, irql);
39}
40
41bool semaphore_timedwait(struct semaphore *s,
42 time_ms_t timeout_ms) TSA_NO_ANALYSIS {
43 enum irql irql = semaphore_lock_internal(sem: s);
44
45 while (s->count == 0) {
46 enum wake_reason wr =
47 condvar_wait_timeout(cv: &s->cv, lock: &s->lock, timeout_ms, irql, out: &irql);
48 if (wr == WAKE_REASON_TIMEOUT && s->count == 0) {
49 spin_unlock(&s->lock, irql);
50 return false;
51 }
52 }
53
54 s->count--;
55 spin_unlock(&s->lock, irql);
56
57 return true;
58}
59
60void semaphore_post(struct semaphore *s) TSA_NO_ANALYSIS {
61 enum irql irql = semaphore_lock_internal(sem: s);
62
63 s->count++;
64
65 condvar_signal(cv: &s->cv);
66
67 spin_unlock(&s->lock, irql);
68}
69
70void semaphore_postn(struct semaphore *s, int n) TSA_NO_ANALYSIS {
71 enum irql irql = semaphore_lock_internal(sem: s);
72
73 s->count += n;
74 for (int i = 0; i < n; i++)
75 condvar_signal(cv: &s->cv);
76
77 spin_unlock(&s->lock, irql);
78}
79