sweep through entire page table to free up intermediate tables
[lunaix-os.git] / lunaix-os / kernel / ds / waitq.c
1 #include <lunaix/ds/waitq.h>
2 #include <lunaix/process.h>
3 #include <lunaix/sched.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/kpreempt.h>
6
7 static inline void must_inline
8 __try_wait(bool check_stall) 
9 {
10     unsigned int nstall;
11     waitq_t* current_wq = &current_thread->waitqueue;
12     if (waitq_empty(current_wq)) {
13         return;
14     }
15     
16     block_current_thread();
17
18     if (!check_stall) {
19         // if we are not checking stall, we give up voluntarily
20         yield_current();
21     } else {
22         // otherwise, treat it as being preempted by kernel
23         preempt_current();
24     }
25
26     // In case of SIGINT-forced awaken
27     llist_delete(&current_wq->waiters);
28 }
29
30 static inline void must_inline
31 __pwait(waitq_t* queue, bool check_stall)
32 {
33     // prevent race condition.
34     no_preemption();
35
36     prepare_to_wait(queue);
37     __try_wait(check_stall);
38
39     set_preemption();
40 }
41
42 void
43 pwait(waitq_t* queue)
44 {
45     __pwait(queue, false);
46 }
47
48 void
49 pwait_check_stall(waitq_t* queue)
50 {
51     __pwait(queue, true);
52 }
53
54 void
55 pwake_one(waitq_t* queue)
56 {
57     if (llist_empty(&queue->waiters)) {
58         return;
59     }
60
61     waitq_t* wq = list_entry(queue->waiters.next, waitq_t, waiters);
62     struct thread* thread = container_of(wq, struct thread, waitqueue);
63
64     assert(thread->state == PS_BLOCKED);
65     thread->state = PS_READY;
66     llist_delete(&wq->waiters);
67 }
68
69 void
70 pwake_all(waitq_t* queue)
71 {
72     if (llist_empty(&queue->waiters)) {
73         return;
74     }
75
76     struct thread* thread;
77     waitq_t *pos, *n;
78     llist_for_each(pos, n, &queue->waiters, waiters)
79     {
80         thread = container_of(pos, struct thread, waitqueue);
81
82         if (thread->state == PS_BLOCKED) {
83             thread->state = PS_READY;
84         }
85         
86         // already awaken or killed by other event, just remove it
87         llist_delete(&pos->waiters);
88     }
89 }
90
91 void
92 prepare_to_wait(waitq_t* queue)
93 {
94     assert(current_thread);
95     
96     waitq_t* current_wq = &current_thread->waitqueue;
97     assert(llist_empty(&current_wq->waiters));
98
99     llist_append(&queue->waiters, &current_wq->waiters);
100 }
101
102 void
103 try_wait()
104 {
105     __try_wait(false);
106 }
107
108 void
109 try_wait_check_stall()
110 {
111     __try_wait(true);
112 }