MOS Source Code
Loading...
Searching...
No Matches
schedule.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
4
5#include "mos/assert.hpp"
7#include "mos/misc/setup.hpp"
10#include "mos/tasks/thread.hpp"
11
12#include <mos_string.hpp>
13
15{
16 switch (state)
17 {
18 case THREAD_STATE_CREATED: return 'C';
19 case THREAD_STATE_READY: return 'R';
20 case THREAD_STATE_RUNNING: return 'r';
21 case THREAD_STATE_BLOCKED: return 'B';
22 case THREAD_STATE_NONINTERRUPTIBLE: return 'N';
23 case THREAD_STATE_DEAD: return 'D';
24 }
25
27}
28
29static bool scheduler_ready = false;
32
33MOS_SETUP("scheduler", scheduler_cmdline_selector)
34{
35 for (const scheduler_info_t *info = __MOS_SCHEDULERS_START; info < __MOS_SCHEDULERS_END; info++)
36 {
37 if (strcmp(info->name, arg) == 0)
38 {
39 active_scheduler = info->scheduler;
41 pr_dinfo2(scheduler, "active scheduler: %s", info->name);
42 return true;
43 }
44 }
45
46 pr_dwarn(scheduler, "scheduler '%s' not found", arg);
47 return false;
48}
49
51{
53 {
54 pr_dwarn(scheduler, "no scheduler is selected, using the first scheduler");
57 }
58}
59
61{
62 pr_dinfo2(scheduler, "unblocking scheduler");
63 MOS_ASSERT_X(!scheduler_ready, "scheduler is already unblocked");
64 scheduler_ready = true;
65}
66
67[[noreturn]] void enter_scheduler(void)
68{
69 while (likely(!scheduler_ready))
70 ; // wait for the scheduler to be unblocked
71
72 pr_dinfo2(scheduler, "cpu %d: scheduler is ready", platform_current_cpu_id());
73 MOS_ASSERT(current_thread == nullptr);
74 reschedule();
76}
77
79{
81 MOS_ASSERT_X(thread->state == THREAD_STATE_CREATED || thread->state == THREAD_STATE_READY, "thread %pt is not in a valid state", thread);
82 active_scheduler->ops->add_thread(active_scheduler, thread);
83}
84
86{
88 active_scheduler->ops->remove_thread(active_scheduler, thread);
89}
90
92{
94 if (thread->state == THREAD_STATE_READY || thread->state == THREAD_STATE_RUNNING || thread->state == THREAD_STATE_CREATED || thread->state == THREAD_STATE_DEAD)
95 {
97 return; // thread is already running or ready
98 }
99
100 MOS_ASSERT_X(thread->state == THREAD_STATE_BLOCKED || thread->state == THREAD_STATE_NONINTERRUPTIBLE, "thread %pt is not blocked", thread);
101 thread->state = THREAD_STATE_READY;
103 pr_dinfo2(scheduler, "waking up %pt", thread);
104 active_scheduler->ops->add_thread(active_scheduler, thread);
105}
106
107void reschedule(void)
108{
109 // A thread can jump to the scheduler if it is:
110 // - in RUNNING state normal condition (context switch caused by timer interrupt or yield())
111 // - in CREATED state the thread is not yet started
112 // - in DEAD state the thread is exiting, and the scheduler will clean it up
113 // - in BLOCKED state the thread is waiting for a condition, and we'll schedule to other threads
114 // But it can't be:
115 // - in READY state
116 cpu_t *cpu = current_cpu;
117
118 auto next = active_scheduler->ops->select_next(active_scheduler);
119
120 if (!next)
121 {
123 {
124 // give the current thread another chance to run, if it's the only one and it's able to run
125 MOS_ASSERT_X(spinlock_is_locked(&current_thread->state_lock), "thread state lock must be held");
126 pr_dinfo2(scheduler, "no thread to run, staying with %pt, state = %c", current_thread, thread_state_str(current_thread->state));
127 spinlock_release(&current_thread->state_lock);
128 return;
129 }
130
131 next = cpu->idle_thread;
132 }
133
134 const bool should_switch_mm = cpu->mm_context != next->owner->mm;
135 if (should_switch_mm)
136 {
137 MMContext *old = mm_switch_context(next->owner->mm);
138 MOS_UNUSED(old);
139 }
140
141 const switch_flags_t switch_flags = statement_expr(switch_flags_t, {
142 retval = SWITCH_REGULAR;
143 if (next->state == THREAD_STATE_CREATED)
145 });
146
148 {
150 {
152 if (current_thread != cpu->idle_thread)
154 }
155 pr_dinfo2(scheduler, "leaving %pt, state: '%c'", current_thread, thread_state_str(current_thread->state));
156 }
157 pr_dinfo2(scheduler, "switching to %pt, state: '%c'", next, thread_state_str(next->state));
158
159 next->state = THREAD_STATE_RUNNING;
160 spinlock_release(&next->state_lock);
161 platform_switch_to_thread(current_thread, next, switch_flags);
162}
163
165{
166 spinlock_acquire(&current_thread->state_lock);
168 pr_dinfo2(scheduler, "%pt is now blocked", current_thread);
169 reschedule();
170}
171
173{
174 MOS_ASSERT_X(current_thread->state != THREAD_STATE_BLOCKED, "thread %d is already blocked", current_thread->tid);
175
176 if (!waitlist_append(waitlist))
177 return false; // waitlist is closed, process is dead
178
180 return true;
181}
#define MOS_ASSERT_X(cond, msg,...)
Definition assert.hpp:15
#define MOS_ASSERT(cond)
Definition assert.hpp:14
#define MOS_UNREACHABLE()
Definition assert.hpp:11
MOSAPI s32 strcmp(const char *str1, const char *str2)
__nodiscard MMContext * mm_switch_context(MMContext *new_ctx)
Definition mm.cpp:120
@ THREAD_MODE_KERNEL
#define likely(x)
Definition mos_global.h:39
#define statement_expr(type,...)
Definition mos_global.h:102
#define MOS_UNUSED(x)
Definition mos_global.h:65
#define NULL
Definition pb_syshdr.h:46
#define current_thread
Definition platform.hpp:32
thread_state_t
Definition platform.hpp:66
@ THREAD_STATE_READY
thread can be scheduled
Definition platform.hpp:68
@ THREAD_STATE_RUNNING
thread is currently running
Definition platform.hpp:69
@ THREAD_STATE_NONINTERRUPTIBLE
thread is blocked, and cannot be interrupted
Definition platform.hpp:71
@ THREAD_STATE_DEAD
thread is dead, and will be cleaned up soon by the scheduler
Definition platform.hpp:72
@ THREAD_STATE_BLOCKED
thread is blocked by a wait condition
Definition platform.hpp:70
@ THREAD_STATE_CREATED
created or forked, but not ever started
Definition platform.hpp:67
#define current_cpu
Definition platform.hpp:31
switch_flags_t
Definition platform.hpp:76
@ SWITCH_REGULAR
Definition platform.hpp:77
@ SWITCH_TO_NEW_KERNEL_THREAD
Definition platform.hpp:79
@ SWITCH_TO_NEW_USER_THREAD
Definition platform.hpp:78
#define pr_dinfo2(feat, fmt,...)
Definition printk.hpp:27
#define pr_dwarn(feat, fmt,...)
Definition printk.hpp:30
void platform_switch_to_thread(Thread *current, Thread *new_thread, switch_flags_t switch_flags)
u32 platform_current_cpu_id()
void scheduler_init()
Definition schedule.cpp:50
void blocked_reschedule(void)
Mark the current task as blocked and reschedule.
Definition schedule.cpp:164
bool reschedule_for_waitlist(waitlist_t *waitlist)
Definition schedule.cpp:172
void unblock_scheduler(void)
Unblock the scheduler, so that APs can start scheduling.
Definition schedule.cpp:60
void enter_scheduler(void)
Enter the scheduler and switch to the next thread.
Definition schedule.cpp:67
void reschedule(void)
reschedule.
Definition schedule.cpp:107
char thread_state_str(thread_state_t state)
Definition schedule.cpp:14
static bool scheduler_ready
Definition schedule.cpp:29
const scheduler_info_t __MOS_SCHEDULERS_END[]
Definition schedule.cpp:31
const scheduler_info_t __MOS_SCHEDULERS_START[]
static scheduler_t * active_scheduler
Definition schedule.cpp:30
void scheduler_add_thread(Thread *thread)
Add a thread to the scheduler, so that it can be scheduled.
Definition schedule.cpp:78
void scheduler_remove_thread(Thread *thread)
Remove a thread from the scheduler.
Definition schedule.cpp:85
void scheduler_wake_thread(Thread *thread)
Wake a thread.
Definition schedule.cpp:91
#define MOS_SETUP(_param, _fn)
Definition setup.hpp:33
should_inline bool spinlock_is_locked(const spinlock_t *lock)
Definition spinlock.hpp:71
#define spinlock_acquire(lock)
Definition spinlock.hpp:64
#define spinlock_release(lock)
Definition spinlock.hpp:65
spinlock_t state_lock
protects the thread state
thread_state_t state
thread state
Thread * idle_thread
idle thread for this CPU
Definition platform.hpp:101
MMContext * mm_context
Definition platform.hpp:98
should_inline bool thread_is_valid(const Thread *thread)
Definition thread.hpp:13
__nodiscard bool waitlist_append(waitlist_t *list)
Definition wait.cpp:21