1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/tasks/schedule.hpp"
4
5#include <mos/lib/structures/list.hpp>
6#include <mos/lib/sync/spinlock.hpp>
7#include <mos/platform/platform.hpp>
8#include <mos/syslog/printk.hpp>
9#include <mos/tasks/task_types.hpp>
10#include <mos/tasks/thread.hpp>
11#include <mos/tasks/wait.hpp>
12#include <mos_stdlib.hpp>
13#include <mos_string.hpp>
14
15void waitlist_init(waitlist_t *list)
16{
17 memzero(s: list, n: sizeof(waitlist_t));
18 linked_list_init(head_node: &list->list);
19}
20
21bool waitlist_append(waitlist_t *list)
22{
23 spinlock_acquire(&list->lock);
24 if (list->closed)
25 {
26 spinlock_release(&list->lock);
27 return false;
28 }
29
30 waitable_list_entry_t *entry = mos::create<waitable_list_entry_t>();
31 entry->waiter = current_thread->tid;
32 list_node_append(head: &list->list, list_node(entry));
33 spinlock_release(&list->lock);
34 return true;
35}
36
37size_t waitlist_wake(waitlist_t *list, size_t max_wakeups)
38{
39 spinlock_acquire(&list->lock);
40
41 if (list_is_empty(head: &list->list))
42 {
43 spinlock_release(&list->lock);
44 return 0;
45 }
46
47 size_t wakeups = 0;
48 while (wakeups < max_wakeups && !list_is_empty(head: &list->list))
49 {
50 list_node_t *node = list_node_pop(head: &list->list);
51 waitable_list_entry_t *entry = list_entry(node, waitable_list_entry_t);
52
53 Thread *thread = thread_get(id: entry->waiter);
54 if (thread) // if the thread is still there
55 {
56 if (thread->state == THREAD_STATE_BLOCKED)
57 scheduler_wake_thread(thread);
58 }
59 delete entry;
60 wakeups++;
61 }
62
63 spinlock_release(&list->lock);
64
65 return wakeups;
66}
67
68void waitlist_close(waitlist_t *list)
69{
70 spinlock_acquire(&list->lock);
71 if (list->closed)
72 pr_warn("waitlist already closed");
73
74 list->closed = true;
75 spinlock_release(&list->lock);
76}
77
78void waitlist_remove_me(waitlist_t *waitlist)
79{
80 spinlock_acquire(&waitlist->lock);
81
82 list_foreach(waitable_list_entry_t, entry, waitlist->list)
83 {
84 if (entry->waiter == current_thread->tid)
85 {
86 list_remove(entry);
87 delete entry;
88 break;
89 }
90 }
91
92 spinlock_release(&waitlist->lock);
93}
94
95waitlist_t::waitlist_t()
96{
97 waitlist_init(list: this);
98}
99