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