CS350 COS
COS
Loading...
Searching...
No Matches
thread.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/*
26 * Unfortunately the thread, process and scheduler code are pretty well
27 * integrated. To avoid poluting the global namespace we import a few symbols
28 * from sched.c and process.c that are required during initialization and
29 * regular execution of the thread code.
30 */
31
32/* Globals declared in sched.c */
33extern Spinlock schedLock;
34extern ThreadQueue waitQueue;
35extern ThreadQueue runnableQueue;
36extern Thread *curProc[MAX_CPUS];
37
38/* Globals declared in process.c */
39extern Spinlock procLock;
41extern ProcessQueue processList;
42extern Slab processSlab;
43
44// Special Kernel Process
46
47// Memory Pools
49
51
52void
54{
55 nextProcessID = 1;
56
57 Slab_Init(&processSlab, "Process Objects", sizeof(Process), 16);
58 Slab_Init(&threadSlab, "Thread Objects", sizeof(Thread), 16);
59
60 Spinlock_Init(&procLock, "Process List Lock", SPINLOCK_TYPE_NORMAL);
62
66
68
69 // Kernel Process
71
72 // Create an thread object for current context
73 Process *proc = Process_Create(NULL, "init");
74 curProc[0] = Thread_Create(proc);
76}
77
78void
80{
82
84
85 //PAlloc_Release((void *)thr->kstack);
86 //thr->kstack = 0;
87
88 curProc[CPU()] = apthr;
89}
90
91/*
92 * Thread
93 */
94
95Thread *
97{
99
100 if (!thr)
101 return NULL;
102
103 memset(thr, 0, sizeof(*thr));
104
105 ASSERT(proc != NULL);
106
107 thr->tid = proc->nextThreadID++;
109 if (thr->kstack == 0) {
110 Slab_Free(&threadSlab, thr);
111 return NULL;
112 }
113
114 Process_Retain(proc);
115
116 Spinlock_Lock(&proc->lock);
117 thr->proc = proc;
118 proc->threads++;
119 TAILQ_INSERT_TAIL(&proc->threadList, thr, threadList);
120 thr->space = proc->space;
121 thr->ustack = proc->ustackNext;
123 Spinlock_Unlock(&proc->lock);
124
126 thr->timerEvt = NULL;
127 thr->refCount = 1;
128
129 Thread_InitArch(thr);
130 // Initialize queue
131
132 return thr;
133}
134
135Thread *
136Thread_KThreadCreate(void (*f)(void *), void *arg)
137{
139 if (!thr)
140 return NULL;
141
142 Thread_SetupKThread(thr, f, (uintptr_t)arg, 0, 0);
143
144 return thr;
145}
146
147Thread *
149{
150 Process *proc = oldThr->proc;
152
153 if (!thr)
154 return NULL;
155
156 memset(thr, 0, sizeof(*thr));
157
158 thr->tid = proc->nextThreadID++;
160 if (thr->kstack == 0) {
161 Slab_Free(&threadSlab, thr);
162 return NULL;
163 }
164
165 thr->space = oldThr->space;
167 thr->refCount = 1;
168
169 Spinlock_Lock(&proc->lock);
170 thr->ustack = proc->ustackNext;
172 Spinlock_Unlock(&proc->lock);
173
175 // XXX: Check failure
176
177 Thread_InitArch(thr);
178 // Initialize queue
179
180 Thread_SetupUThread(thr, rip, arg);
181
182 Process_Retain(proc);
183
184 Spinlock_Lock(&proc->lock);
185 thr->proc = proc;
186 // XXX: Process lock
187 proc->threads++;
188 TAILQ_INSERT_TAIL(&proc->threadList, thr, threadList);
189 Spinlock_Unlock(&proc->lock);
190
191 return thr;
192}
193
194static void
196{
197 Process *proc = thr->proc;
198
199 // Don't free kernel threads
200 ASSERT(proc->pid != 1);
201
202 // Free userspace stack
203
204 Spinlock_Lock(&proc->lock);
205 proc->threads--;
206 TAILQ_REMOVE(&proc->threadList, thr, threadList);
207 Spinlock_Unlock(&proc->lock);
208
209 // Free AS
210 PAlloc_Release((void *)thr->kstack);
211
212 // Release process handle
213 Process_Release(thr->proc);
214
215 Slab_Free(&threadSlab, thr);
216}
217
228Thread *
230{
231 Thread *t;
232 Thread *thr = NULL;
233
234 Spinlock_Lock(&proc->lock);
235 TAILQ_FOREACH(t, &proc->threadList, threadList) {
236 if (t->tid == tid) {
237 Thread_Retain(t);
238 thr = t;
239 break;
240 }
241 }
242 Spinlock_Unlock(&proc->lock);
243
244 return thr;
245}
246
252void
254{
255 ASSERT(thr->refCount != 0);
256 __sync_fetch_and_add(&thr->refCount, 1);
257}
258
264void
266{
267 ASSERT(thr->refCount != 0);
268 if (__sync_fetch_and_sub(&thr->refCount, 1) == 1) {
269 Thread_Destroy(thr);
270 }
271}
272
280{
281 Thread *t;
282 uint64_t status;
283
284 ASSERT(thr->proc != NULL);
285
286 if (tid == TID_ANY) {
287 t = TAILQ_FIRST(&thr->proc->zombieQueue);
288 if (!t) {
289 return SYSCALL_PACK(EAGAIN, 0);
290 }
291
292 TAILQ_REMOVE(&thr->proc->zombieQueue, t, schedQueue);
293 status = t->exitValue;
295 return SYSCALL_PACK(0, status);
296 }
297
298 // XXXURGENT
299 TAILQ_FOREACH(t, &thr->proc->zombieQueue, schedQueue) {
300 if (t->tid == tid) {
301 TAILQ_REMOVE(&thr->proc->zombieQueue, t, schedQueue);
302 status = t->exitValue;
304 return SYSCALL_PACK(0, status);
305 }
306 }
307
308 return 0;
309}
310
312
313void
315{
316 TSS[CPU()].rsp0 = curProc[CPU()]->kstack + 4096;
317
319
320 Trap_Pop(tf);
321}
322
323/*
324 * Debugging
325 */
326
327void
329{
330 const char *states[] = {
331 "NULL",
332 "RUNNABLE",
333 "RUNNING",
334 "WAITING",
335 "ZOMBIE"
336 };
337
338 // Thread_DumpArch(thr)
339 kprintf("space %016llx\n", thr->space);
340 kprintf("kstack %016llx\n", thr->kstack);
341 kprintf("tid %llu\n", thr->tid);
342 kprintf("refCount %d\n", thr->refCount);
343 kprintf("state %s\n", states[thr->schedState]);
344 kprintf("ctxswtch %llu\n", thr->ctxSwitches);
345 kprintf("utime %llu\n", thr->userTime);
346 kprintf("ktime %llu\n", thr->kernTime);
347 kprintf("wtime %llu\n", thr->waitTime);
348 if (thr->proc) {
349 Process_Dump(thr->proc);
350 }
351}
352
353static void
354Debug_Threads(int argc, const char *argv[])
355{
356 Thread *thr;
357
358 //Spinlock_Lock(&threadLock);
359
360 for (int i = 0; i < MAX_CPUS; i++) {
361 thr = curProc[i];
362 if (thr) {
363 kprintf("Running Thread CPU %d: %d(%016llx) %d\n", i, thr->tid, thr, thr->ctxSwitches);
364 Thread_Dump(thr);
365 }
366 }
367 TAILQ_FOREACH(thr, &runnableQueue, schedQueue)
368 {
369 kprintf("Runnable Thread: %d(%016llx) %d\n", thr->tid, thr, thr->ctxSwitches);
370 Thread_Dump(thr);
371 }
372 TAILQ_FOREACH(thr, &waitQueue, schedQueue)
373 {
374 kprintf("Waiting Thread: %d(%016llx) %d\n", thr->tid, thr, thr->ctxSwitches);
375 Thread_Dump(thr);
376 }
377
378 //Spinlock_Unlock(&threadLock);
379}
380
381REGISTER_DBGCMD(threads, "Display list of threads", Debug_Threads);
382
383static void
384Debug_ThreadInfo(int argc, const char *argv[])
385{
386 Thread *thr = curProc[CPU()];
387
388 kprintf("Current Thread State:\n");
389 Thread_Dump(thr);
390}
391
392REGISTER_DBGCMD(threadinfo, "Display current thread state", Debug_ThreadInfo);
393
void Thread_SetupUThread(Thread *thr, uintptr_t rip, uintptr_t arg)
Definition: thread.c:75
void Thread_SetupKThread(Thread *thr, void(*f)(), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
Definition: thread.c:26
TaskStateSegment64 TSS[MAX_CPUS]
Definition: machine.c:40
void ThreadKThreadEntry(TrapFrame *tf)
Definition: thread.c:314
void Thread_InitArch(Thread *thr)
Definition: thread.c:20
#define PTE_W
Definition: amd64.h:36
uint64_t rsp0
Definition: amd64.h:108
#define __NO_LOCK_ANALYSIS
Definition: cdefs.h:31
#define EAGAIN
Definition: errno.h:19
#define CPU
Definition: mp.h:7
#define SCHED_STATE_RUNNING
Definition: thread.h:27
Process * Process_Create(Process *parent, const char *title)
Definition: process.c:50
void Process_Dump(Process *proc)
Definition: process.c:251
void Process_Retain(Process *proc)
Definition: process.c:171
void Process_Release(Process *proc)
Definition: process.c:185
#define SCHED_STATE_NULL
Definition: thread.h:25
#define TID_ANY
Definition: thread.h:106
#define ASSERT(_x)
Definition: kassert.h:8
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define MAX_CPUS
Definition: kconfig.h:8
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
Thread * Thread_KThreadCreate(void(*f)(void *), void *arg)
Definition: thread.c:136
ProcessQueue processList
Definition: process.c:30
Thread * Thread_Create(Process *proc)
Definition: thread.c:96
Thread * Thread_UThreadCreate(Thread *oldThr, uint64_t rip, uint64_t arg)
Definition: thread.c:148
uint64_t nextProcessID
Definition: process.c:29
void Thread_Release(Thread *thr)
Definition: thread.c:265
static void Debug_Threads(int argc, const char *argv[])
Definition: thread.c:354
ThreadQueue runnableQueue
Definition: sched.c:37
static void Thread_Destroy(Thread *thr)
Definition: thread.c:195
static void Debug_ThreadInfo(int argc, const char *argv[])
Definition: thread.c:384
Thread * curProc[MAX_CPUS]
Definition: sched.c:41
Slab threadSlab
Definition: thread.c:48
void Thread_Init()
Definition: thread.c:53
void Thread_Dump(Thread *thr)
Definition: thread.c:328
void Handle_GlobalInit()
Definition: handle.c:15
Spinlock procLock
Definition: process.c:28
Spinlock schedLock
Definition: sched.c:29
uint64_t Thread_Wait(Thread *thr, uint64_t tid)
Definition: thread.c:279
void Thread_InitAP()
Definition: thread.c:79
Thread * Thread_Lookup(Process *proc, uint64_t tid)
Definition: thread.c:229
Slab processSlab
Definition: process.c:33
Process * kernelProcess
Definition: thread.c:45
ThreadQueue waitQueue
Definition: sched.c:33
void Thread_Retain(Thread *thr)
Definition: thread.c:253
void PAlloc_Release(void *pg)
Definition: palloc.c:265
void Slab_Free(Slab *slab, void *obj)
Definition: slab.c:135
void * PAlloc_AllocPage()
Definition: palloc.c:188
void * Slab_Alloc(Slab *slab) __attribute__((malloc))
Definition: slab.c:105
void Slab_Init(Slab *slab, const char *name, uintptr_t objsz, uintptr_t align)
#define MEM_USERSPACE_STKLEN
Definition: pmap.h:37
bool PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags)
Definition: pmap.c:423
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:557
#define TAILQ_INIT(head)
Definition: queue.h:597
#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 Spinlock_Unlock(Spinlock *lock) __UNLOCK_EX(*lock)
Definition: spinlock.c:109
#define SPINLOCK_TYPE_NORMAL
Definition: spinlock.h:12
#define SPINLOCK_TYPE_RECURSIVE
Definition: spinlock.h:13
void Spinlock_Lock(Spinlock *lock) __LOCK_EX(*lock)
Definition: spinlock.c:75
void Spinlock_Init(Spinlock *lock, const char *name, uint64_t type)
Definition: spinlock.c:43
#define NULL
Definition: stddef.h:6
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
Definition: thread.h:65
Spinlock lock
Definition: thread.h:68
ThreadQueue threadList
Definition: thread.h:87
uintptr_t ustackNext
Definition: thread.h:71
uint64_t nextThreadID
Definition: thread.h:70
ThreadQueue zombieQueue
Definition: thread.h:89
uint64_t threads
Definition: thread.h:86
uint64_t pid
Definition: thread.h:66
AS * space
Definition: thread.h:67
Definition: kmem.h:46
Definition: thread.h:31
uint64_t ctxSwitches
Definition: thread.h:51
uint64_t kernTime
Definition: thread.h:53
struct Process * proc
Definition: thread.h:39
uint64_t refCount
Definition: thread.h:37
uintptr_t ustack
Definition: thread.h:35
uintptr_t exitValue
Definition: thread.h:45
uint64_t waitTime
Definition: thread.h:54
uint64_t userTime
Definition: thread.h:52
AS * space
Definition: thread.h:33
KTimerEvent * timerEvt
Definition: thread.h:44
int schedState
Definition: thread.h:42
uint64_t tid
Definition: thread.h:36
uintptr_t kstack
Definition: thread.h:34
#define SYSCALL_PACK(_errcode, _val)
Definition: syscall.h:55
void Trap_Pop(TrapFrame *tf)
Definition: trap.h:51
uint64_t uintptr_t
Definition: types.h:16
unsigned long uint64_t
Definition: types.h:13