1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/lib/structures/list.hpp"
4#include "mos/platform/platform.hpp"
5#include "mos/tasks/scheduler.hpp"
6#include "mos/tasks/task_types.hpp"
7
8#include <mos/allocator.hpp>
9#include <mos_stdlib.hpp>
10
11typedef struct
12{
13 scheduler_t base;
14 list_head threads; ///< list of runnable threads
15 spinlock_t lock;
16} naive_sched_t;
17
18struct naive_sched_node_t : mos::NamedType<"NaiveSched.Node">
19{
20 as_linked_list;
21 Thread *thread;
22}; ///< Node in the naive scheduler's list of threads
23
24static void naive_sched_init(scheduler_t *instance)
25{
26 naive_sched_t *scheduler = container_of(instance, naive_sched_t, base);
27 spinlock_init(&scheduler->lock);
28 linked_list_init(head_node: &scheduler->threads);
29 pr_dinfo2(naive_sched, "naive scheduler initialized");
30}
31
32static Thread *naive_sched_select_next(scheduler_t *instance)
33{
34 naive_sched_t *scheduler = container_of(instance, naive_sched_t, base);
35
36 spinlock_acquire(&scheduler->lock);
37 if (list_is_empty(head: &scheduler->threads))
38 {
39 spinlock_release(&scheduler->lock);
40 pr_dinfo(naive_sched, "no threads to run");
41 return NULL;
42 }
43
44 naive_sched_node_t *node = list_entry(scheduler->threads.next, naive_sched_node_t);
45 list_remove(node);
46 spinlock_release(&scheduler->lock);
47
48 Thread *thread = node->thread;
49 delete node;
50
51 MOS_ASSERT_X(thread != current_thread, "current thread queued in scheduler");
52 spinlock_acquire(&thread->state_lock);
53
54 pr_dinfo2(naive_sched, "naive scheduler selected thread %pt", thread);
55 return thread;
56}
57
58static void naive_sched_add_thread(scheduler_t *instance, Thread *thread)
59{
60 naive_sched_t *scheduler = container_of(instance, naive_sched_t, base);
61
62 pr_dinfo(naive_sched, "adding thread %pt to scheduler", thread);
63
64 naive_sched_node_t *node = mos::create<naive_sched_node_t>();
65 linked_list_init(list_node(node));
66 node->thread = thread;
67
68 spinlock_acquire(&scheduler->lock);
69 list_node_append(head: &scheduler->threads, list_node(node));
70 spinlock_release(&scheduler->lock);
71}
72
73static void naive_sched_remove_thread(scheduler_t *instance, Thread *thread)
74{
75 pr_dinfo2(naive_sched, "naive scheduler removed thread %pt", thread);
76
77 naive_sched_t *scheduler = container_of(instance, naive_sched_t, base);
78 spinlock_acquire(&scheduler->lock);
79 list_foreach(naive_sched_node_t, node, scheduler->threads)
80 {
81 if (node->thread == thread)
82 {
83 list_remove(node);
84 delete node;
85 break;
86 }
87 }
88 spinlock_release(&scheduler->lock);
89}
90
91static const scheduler_ops_t naive_sched_ops = {
92 .init = naive_sched_init,
93 .select_next = naive_sched_select_next,
94 .add_thread = naive_sched_add_thread,
95 .remove_thread = naive_sched_remove_thread,
96};
97
98static naive_sched_t naive_sched = {
99 .base = { .ops = &naive_sched_ops },
100};
101
102MOS_SCHEDULER(naive, naive_sched.base);
103