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 | |
17 | slab_t *waitlist_slab = NULL; |
18 | SLAB_AUTOINIT("waitlist" , waitlist_slab, waitlist_t); |
19 | |
20 | static slab_t *waitlist_listentry_slab = NULL; |
21 | SLAB_AUTOINIT("waitlist_entry" , waitlist_listentry_slab, waitable_list_entry_t); |
22 | |
23 | void waitlist_init(waitlist_t *list) |
24 | { |
25 | memzero(s: list, n: sizeof(waitlist_t)); |
26 | linked_list_init(head_node: &list->list); |
27 | } |
28 | |
29 | bool 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 | |
45 | size_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 | |
76 | void 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 | |
86 | void 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 | |