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