MOS Source Code
Loading...
Searching...
No Matches
schedule.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
4
5#include "mos/assert.h"
7#include "mos/misc/setup.h"
10#include "mos/tasks/thread.h"
11
12#include <mos_string.h>
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());
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", (void *) thread);
83}
84
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", (void *) thread);
101 thread->state = THREAD_STATE_READY;
103 pr_dinfo2(scheduler, "waking up %pt", (void *) 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 thread_t *const current = cpu->thread;
118
120
121 if (!next)
122 {
123 if (current && current->state == THREAD_STATE_RUNNING)
124 {
125 // give the current thread another chance to run, if it's the only one and it's able to run
126 MOS_ASSERT_X(spinlock_is_locked(&current->state_lock), "thread state lock must be held");
127 pr_dinfo2(scheduler, "no thread to run, staying with %pt, state = %c", (void *) current, thread_state_str(current->state));
128 spinlock_release(&current->state_lock);
129 return;
130 }
131
132 next = cpu->idle_thread;
133 }
134
135 const bool should_switch_mm = cpu->mm_context != next->owner->mm;
136 if (should_switch_mm)
137 {
138 mm_context_t *old = mm_switch_context(next->owner->mm);
139 MOS_UNUSED(old);
140 }
141
142 const switch_flags_t switch_flags = statement_expr(switch_flags_t, {
143 retval = SWITCH_REGULAR;
144 if (next->state == THREAD_STATE_CREATED)
146 });
147
148 if (likely(current))
149 {
150 if (current->state == THREAD_STATE_RUNNING)
151 {
153 if (current != cpu->idle_thread)
155 }
156 pr_dinfo2(scheduler, "leaving %pt, state: '%c'", (void *) current, thread_state_str(current->state));
157 }
158 pr_dinfo2(scheduler, "switching to %pt, state: '%c'", (void *) next, thread_state_str(next->state));
159
162 platform_switch_to_thread(current, next, switch_flags);
163}
164
166{
167 thread_t *t = current_cpu->thread;
170 pr_dinfo2(scheduler, "%pt is now blocked", (void *) t);
171 reschedule();
172}
173
175{
176 thread_t *t = current_cpu->thread;
177 MOS_ASSERT_X(t->state != THREAD_STATE_BLOCKED, "thread %d is already blocked", t->tid);
178
179 if (!waitlist_append(waitlist))
180 return false; // waitlist is closed, process is dead
181
183 return true;
184}
#define MOS_ASSERT_X(cond, msg,...)
Definition assert.h:15
#define MOS_ASSERT(cond)
Definition assert.h:14
#define MOS_UNREACHABLE()
Definition assert.h:11
MOSAPI s32 strcmp(const char *str1, const char *str2)
Definition mos_string.c:24
__nodiscard mm_context_t * mm_switch_context(mm_context_t *new_ctx)
Definition mm.c:127
@ THREAD_MODE_KERNEL
Definition task_types.h:21
#define likely(x)
Definition mos_global.h:39
#define statement_expr(type,...)
Definition mos_global.h:92
#define MOS_UNUSED(x)
Definition mos_global.h:64
#define current
#define NULL
Definition pb_syshdr.h:46
#define current_thread
Definition platform.h:30
thread_state_t
Definition platform.h:61
@ THREAD_STATE_READY
thread can be scheduled
Definition platform.h:63
@ THREAD_STATE_RUNNING
thread is currently running
Definition platform.h:64
@ THREAD_STATE_NONINTERRUPTIBLE
thread is blocked, and cannot be interrupted
Definition platform.h:66
@ THREAD_STATE_DEAD
thread is dead, and will be cleaned up soon by the scheduler
Definition platform.h:67
@ THREAD_STATE_BLOCKED
thread is blocked by a wait condition
Definition platform.h:65
@ THREAD_STATE_CREATED
created or forked, but not ever started
Definition platform.h:62
#define current_cpu
Definition platform.h:29
switch_flags_t
Definition platform.h:71
@ SWITCH_REGULAR
Definition platform.h:72
@ SWITCH_TO_NEW_KERNEL_THREAD
Definition platform.h:74
@ SWITCH_TO_NEW_USER_THREAD
Definition platform.h:73
#define pr_dinfo2(feat, fmt,...)
Definition printk.h:27
#define pr_dwarn(feat, fmt,...)
Definition printk.h:30
u32 platform_current_cpu_id()
void platform_switch_to_thread(thread_t *current, thread_t *new_thread, switch_flags_t switch_flags)
void scheduler_init()
Definition schedule.c:50
void blocked_reschedule(void)
Mark the current task as blocked and reschedule.
Definition schedule.c:165
bool reschedule_for_waitlist(waitlist_t *waitlist)
Definition schedule.c:174
void unblock_scheduler(void)
Unblock the scheduler, so that APs can start scheduling.
Definition schedule.c:60
void enter_scheduler(void)
Enter the scheduler and switch to the next thread.
Definition schedule.c:67
void scheduler_wake_thread(thread_t *thread)
Wake a thread.
Definition schedule.c:91
void reschedule(void)
reschedule.
Definition schedule.c:107
char thread_state_str(thread_state_t state)
Definition schedule.c:14
static bool scheduler_ready
Definition schedule.c:29
const scheduler_info_t __MOS_SCHEDULERS_END[]
Definition schedule.c:31
void scheduler_add_thread(thread_t *thread)
Add a thread to the scheduler, so that it can be scheduled.
Definition schedule.c:78
const scheduler_info_t __MOS_SCHEDULERS_START[]
static scheduler_t * active_scheduler
Definition schedule.c:30
void scheduler_remove_thread(thread_t *thread)
Remove a thread from the scheduler.
Definition schedule.c:85
#define MOS_SETUP(_param, _fn)
Definition setup.h:35
should_inline bool spinlock_is_locked(const spinlock_t *lock)
Definition spinlock.h:68
#define spinlock_acquire(lock)
Definition spinlock.h:61
#define spinlock_release(lock)
Definition spinlock.h:62
thread_t * thread
Definition platform.h:91
mm_context_t * mm_context
Definition platform.h:93
thread_t * idle_thread
idle thread for this CPU
Definition platform.h:96
mm_context_t * mm
Definition task_types.h:59
scheduler_t *const scheduler
Definition scheduler.h:31
void(* remove_thread)(scheduler_t *instance, thread_t *thread)
Remove a thread from the scheduler.
Definition scheduler.h:20
void(* init)(scheduler_t *instance)
Initialize the scheduler.
Definition scheduler.h:12
thread_t *(* select_next)(scheduler_t *instance)
Select the next thread to run, thread state lock should be locked.
Definition scheduler.h:18
void(* add_thread)(scheduler_t *instance, thread_t *thread)
Add a thread to the scheduler.
Definition scheduler.h:19
const scheduler_ops_t * ops
Definition scheduler.h:25
thread_mode mode
user-mode thread or kernel-mode
Definition task_types.h:81
spinlock_t state_lock
protects the thread state
Definition task_types.h:82
process_t * owner
Definition task_types.h:79
tid_t tid
Definition task_types.h:77
thread_state_t state
thread state
Definition task_types.h:83
should_inline bool thread_is_valid(const thread_t *thread)
Definition thread.h:13
__nodiscard bool waitlist_append(waitlist_t *list)
Definition wait.c:29