#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)
{
- assert(current_thread);
- // prevent race condition.
- cpu_disable_interrupt();
-
+ unsigned int nstall;
waitq_t* current_wq = ¤t_thread->waitqueue;
- assert(llist_empty(¤t_wq->waiters));
-
- llist_append(&queue->waiters, ¤t_wq->waiters);
+ if (waitq_empty(current_wq)) {
+ return;
+ }
block_current_thread();
- sched_pass();
+
+ 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(¤t_wq->waiters);
- cpu_enable_interrupt();
+}
+
+static inline void must_inline
+__pwait(waitq_t* queue, bool check_stall)
+{
+ // prevent race condition.
+ no_preemption();
+
+ prepare_to_wait(queue);
+ __try_wait(check_stall);
+
+ set_preemption();
+}
+
+void
+pwait(waitq_t* queue)
+{
+ __pwait(queue, false);
+}
+
+void
+pwait_check_stall(waitq_t* queue)
+{
+ __pwait(queue, true);
}
void
pwake_one(waitq_t* queue)
{
- if (llist_empty(&queue->waiters)) {
+ if (waitq_empty(queue)) {
return;
}
void
pwake_all(waitq_t* queue)
{
- if (llist_empty(&queue->waiters)) {
+ if (waitq_empty(queue)) {
return;
}
{
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);
}
-}
\ No newline at end of file
+}
+
+void
+prepare_to_wait(waitq_t* queue)
+{
+ assert(current_thread);
+
+ waitq_t* current_wq = ¤t_thread->waitqueue;
+ assert(llist_empty(¤t_wq->waiters));
+
+ llist_append(&queue->waiters, ¤t_wq->waiters);
+}
+
+void
+try_wait()
+{
+ __try_wait(false);
+}
+
+void
+try_wait_check_stall()
+{
+ __try_wait(true);
+}