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