CS350 COS
COS
Loading...
Searching...
No Matches
sched.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013-2023 Ali Mashtizadeh
3 * All rights reserved.
4 */
5
6#include <stdbool.h>
7#include <stdint.h>
8#include <string.h>
9
10#include <errno.h>
11#include <sys/syscall.h>
12
13#include <sys/kassert.h>
14#include <sys/kconfig.h>
15#include <sys/kdebug.h>
16#include <sys/kmem.h>
17#include <sys/ktime.h>
18#include <sys/mp.h>
19#include <sys/spinlock.h>
20#include <sys/thread.h>
21
22#include <machine/trap.h>
23#include <machine/pmap.h>
24
25// Scheduler Queues
33ThreadQueue waitQueue;
37ThreadQueue runnableQueue;
42
43/*
44 * Scheduler Functions
45 */
46
55Thread *
57{
59
60 Thread *thr = curProc[CPU()];
61 Thread_Retain(thr);
62
64
65 return thr;
66}
67
76void
78{
80
81 if (thr->proc->procState == PROC_STATE_NULL)
83
84 if (thr->schedState == SCHED_STATE_WAITING) {
85 thr->waitTime += KTime_GetEpochNS() - thr->waitStart;
86 thr->waitStart = 0;
87 TAILQ_REMOVE(&waitQueue, thr, schedQueue);
88 }
90 TAILQ_INSERT_TAIL(&runnableQueue, thr, schedQueue);
91
93}
94
103void
105{
107
109
111 TAILQ_INSERT_TAIL(&waitQueue, thr, schedQueue);
113
115}
116
125void
127{
128 Process *proc = thr->proc;
129
130 /*
131 * Do not go to sleep holding spinlocks.
132 */
133 ASSERT(Critical_Level() == 0);
134
135 if (proc->threads == 1) {
136 // All processes have parents except 'init' and 'kernel'
137 ASSERT(proc->parent != NULL);
139 Spinlock_Lock(&proc->parent->lock); // Guards child list
141 TAILQ_REMOVE(&proc->parent->childrenList, proc, siblingList);
142 TAILQ_INSERT_TAIL(&proc->parent->zombieProc, proc, siblingList);
143 Spinlock_Unlock(&proc->parent->lock);
144 CV_Signal(&proc->zombieProcPCV);
146 }
147
148 /*
149 * Set as zombie just before releasing the zombieProcLock in case we had to
150 * sleep to acquire the zombieProcLock.
151 */
155
156 Spinlock_Lock(&proc->lock);
157 TAILQ_INSERT_TAIL(&proc->zombieQueue, thr, schedQueue);
158 Spinlock_Unlock(&proc->lock);
159
160 if (proc->threads == 1)
162}
163
174static void
175Sched_Switch(Thread *oldthr, Thread *newthr)
176{
177 // Load AS
178 PMap_LoadAS(newthr->space);
179
180 Thread_SwitchArch(oldthr, newthr);
181}
182
188void
190{
191 Thread *prev;
192 Thread *next;
193
195
196 // Select next thread
197 next = TAILQ_FIRST(&runnableQueue);
198 if (!next) {
199 /*
200 * There may be no other runnable processes on this core. This is a
201 * good opportunity to migrate threads. We should never hit this case
202 * once the OS is up and running because of the idle threads, but just
203 * in case we should assert that we never return to a zombie or waiting
204 * thread.
205 */
206 ASSERT(curProc[CPU()]->schedState == SCHED_STATE_RUNNING);
208 return;
209 }
211 TAILQ_REMOVE(&runnableQueue, next, schedQueue);
212
213 prev = curProc[CPU()];
214 curProc[CPU()] = next;
216 next->ctxSwitches++;
217
218 if (prev->schedState == SCHED_STATE_RUNNING) {
220 TAILQ_INSERT_TAIL(&runnableQueue, prev, schedQueue);
221 }
222
223 Sched_Switch(prev, next);
224
226}
227
void Thread_SwitchArch(Thread *oldthr, Thread *newthr)
Definition: thread.c:84
uint32_t Critical_Level()
Definition: critical.c:45
void CV_Signal(CV *cv)
Definition: cv.c:59
#define CPU
Definition: mp.h:7
#define PROC_STATE_READY
Definition: thread.h:62
#define SCHED_STATE_RUNNING
Definition: thread.h:27
#define PROC_STATE_ZOMBIE
Definition: thread.h:63
#define SCHED_STATE_WAITING
Definition: thread.h:28
#define PROC_STATE_NULL
Definition: thread.h:61
#define SCHED_STATE_RUNNABLE
Definition: thread.h:26
#define SCHED_STATE_ZOMBIE
Definition: thread.h:29
void Thread_Retain(Thread *thr)
Definition: thread.c:253
#define ASSERT(_x)
Definition: kassert.h:8
#define MAX_CPUS
Definition: kconfig.h:8
UnixEpochNS KTime_GetEpochNS()
Definition: ktime.c:194
void PMap_LoadAS(AS *space)
Definition: pmap.c:182
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:641
#define TAILQ_FIRST(head)
Definition: queue.h:555
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:659
void Sched_SetWaiting(Thread *thr)
Definition: sched.c:104
void Sched_Scheduler()
Definition: sched.c:189
ThreadQueue runnableQueue
Definition: sched.c:37
Thread * curProc[MAX_CPUS]
Definition: sched.c:41
void Sched_SetZombie(Thread *thr)
Definition: sched.c:126
void Sched_SetRunnable(Thread *thr)
Definition: sched.c:77
Spinlock schedLock
Definition: sched.c:29
Thread * Sched_Current()
Definition: sched.c:56
static void Sched_Switch(Thread *oldthr, Thread *newthr)
Definition: sched.c:175
ThreadQueue waitQueue
Definition: sched.c:33
void Spinlock_Unlock(Spinlock *lock) __UNLOCK_EX(*lock)
Definition: spinlock.c:109
void Spinlock_Lock(Spinlock *lock) __LOCK_EX(*lock)
Definition: spinlock.c:75
#define NULL
Definition: stddef.h:6
Definition: thread.h:65
Spinlock lock
Definition: thread.h:68
ProcessQueue zombieProc
Definition: thread.h:81
ThreadQueue zombieQueue
Definition: thread.h:89
uint64_t threads
Definition: thread.h:86
Process * parent
Definition: thread.h:78
CV zombieProcPCV
Definition: thread.h:84
Mutex zombieProcLock
Definition: thread.h:82
int procState
Definition: thread.h:75
CV zombieProcCV
Definition: thread.h:83
ProcessQueue childrenList
Definition: thread.h:80
Definition: thread.h:31
uint64_t ctxSwitches
Definition: thread.h:51
struct Process * proc
Definition: thread.h:39
uint64_t waitTime
Definition: thread.h:54
AS * space
Definition: thread.h:33
uint64_t waitStart
Definition: thread.h:55
int schedState
Definition: thread.h:42
void Mutex_Unlock(Mutex *mtx)
Definition: mutex.c:83
void Mutex_Lock(Mutex *mtx)
Definition: mutex.c:52