Multiuser, Capabilities and Access Controls (#54)
[lunaix-os.git] / lunaix-os / kernel / ds / waitq.c
index c9fb88f3fede01cffd78d3900e33027f05d28457..e67c44d7c1ca7e37c32281f450f3e454e1c63928 100644 (file)
@@ -2,29 +2,59 @@
 #include <lunaix/process.h>
 #include <lunaix/sched.h>
 #include <lunaix/spike.h>
 #include <lunaix/process.h>
 #include <lunaix/sched.h>
 #include <lunaix/spike.h>
+#include <lunaix/kpreempt.h>
 
 
-void
-pwait(waitq_t* queue)
+static inline void must_inline
+__try_wait(bool check_stall) 
+{
+    unsigned int nstall;
+    waitq_t* current_wq = &current_thread->waitqueue;
+    if (waitq_empty(current_wq)) {
+        return;
+    }
+
+    block_current_thread();
+
+    if (!check_stall) {
+        // if we are not checking stall, we give up voluntarily
+        yield_current();
+    } else {
+        // otherwise, treat it as being preempted by kernel
+        preempt_current();
+    }
+
+    // In case of SIGINT-forced awaken
+    llist_delete(&current_wq->waiters);
+}
+
+static inline void must_inline
+__pwait(waitq_t* queue, bool check_stall)
 {
 {
-    assert(current_thread);
     // prevent race condition.
     // prevent race condition.
-    cpu_disable_interrupt();
+    no_preemption();
 
 
-    waitq_t* current_wq = &current_thread->waitqueue;
-    assert(llist_empty(&current_wq->waiters));
+    prepare_to_wait(queue);
+    __try_wait(check_stall);
 
 
-    llist_append(&queue->waiters, &current_wq->waiters);
+    set_preemption();
+}
 
 
-    block_current_thread();
-    sched_pass();
+void
+pwait(waitq_t* queue)
+{
+    __pwait(queue, false);
+}
 
 
-    cpu_enable_interrupt();
+void
+pwait_check_stall(waitq_t* queue)
+{
+    __pwait(queue, true);
 }
 
 void
 pwake_one(waitq_t* queue)
 {
 }
 
 void
 pwake_one(waitq_t* queue)
 {
-    if (llist_empty(&queue->waiters)) {
+    if (waitq_empty(queue)) {
         return;
     }
 
         return;
     }
 
@@ -39,7 +69,7 @@ pwake_one(waitq_t* queue)
 void
 pwake_all(waitq_t* queue)
 {
 void
 pwake_all(waitq_t* queue)
 {
-    if (llist_empty(&queue->waiters)) {
+    if (waitq_empty(queue)) {
         return;
     }
 
         return;
     }
 
@@ -49,8 +79,34 @@ pwake_all(waitq_t* queue)
     {
         thread = container_of(pos, struct thread, waitqueue);
 
     {
         thread = container_of(pos, struct thread, waitqueue);
 
-        assert(thread->state == PS_BLOCKED);
-        thread->state = PS_READY;
+        if (thread->state == PS_BLOCKED) {
+            thread->state = PS_READY;
+        }
+        
+        // already awaken or killed by other event, just remove it
         llist_delete(&pos->waiters);
     }
         llist_delete(&pos->waiters);
     }
-}
\ No newline at end of file
+}
+
+void
+prepare_to_wait(waitq_t* queue)
+{
+    assert(current_thread);
+    
+    waitq_t* current_wq = &current_thread->waitqueue;
+    assert(llist_empty(&current_wq->waiters));
+
+    llist_append(&queue->waiters, &current_wq->waiters);
+}
+
+void
+try_wait()
+{
+    __try_wait(false);
+}
+
+void
+try_wait_check_stall()
+{
+    __try_wait(true);
+}