Loading [MathJax]/jax/output/HTML-CSS/config.js
CS350 COS
COS
All Data Structures Files Functions Variables Typedefs Macros
thread.h File Reference
#include <sys/queue.h>
#include <sys/handle.h>
#include <sys/ktimer.h>
#include <sys/waitchannel.h>
#include <sys/semaphore.h>
#include <sys/mutex.h>
#include <sys/cv.h>
#include <machine/pmap.h>
#include <machine/thread.h>
Include dependency graph for thread.h:

Go to the source code of this file.

Data Structures

struct  Thread
 
struct  Process
 

Macros

#define SCHED_STATE_NULL   0
 
#define SCHED_STATE_RUNNABLE   1
 
#define SCHED_STATE_RUNNING   2
 
#define SCHED_STATE_WAITING   3
 
#define SCHED_STATE_ZOMBIE   4
 
#define PROCESS_HANDLE_SLOTS   128
 
#define PROCESS_TITLE_LENGTH   128
 
#define PROC_STATE_NULL   0
 
#define PROC_STATE_READY   1
 
#define PROC_STATE_ZOMBIE   2
 
#define TID_ANY   0xFFFFFFFF
 

Typedefs

typedef struct Thread Thread
 
typedef struct Process Process
 

Functions

typedef TAILQ_HEAD (ProcessQueue, Process) ProcessQueue
 
typedef TAILQ_HEAD (ThreadQueue, Thread) ThreadQueue
 
void Thread_Init ()
 
void Thread_InitAP ()
 
ProcessProcess_Create (Process *parent, const char *title)
 
ProcessProcess_Lookup (uint64_t pid)
 
void Process_Retain (Process *proc)
 
void Process_Release (Process *proc)
 
uint64_t Process_Wait (Process *proc, uint64_t pid)
 
ThreadThread_Create (Process *proc)
 
ThreadThread_KThreadCreate (void(*f)(void *), void *arg)
 
ThreadThread_UThreadCreate (Thread *oldThr, uint64_t rip, uint64_t arg)
 
ThreadThread_Lookup (Process *proc, uint64_t tid)
 
void Thread_Retain (Thread *thr)
 
void Thread_Release (Thread *thr)
 
uint64_t Thread_Wait (Thread *thr, uint64_t tid)
 
ThreadSched_Current ()
 
void Sched_SetRunnable (Thread *thr)
 
void Sched_SetWaiting (Thread *thr)
 
void Sched_SetZombie (Thread *thr)
 
void Sched_Scheduler ()
 
void Process_Dump (Process *proc)
 
void Thread_Dump (Thread *thr)
 
void Thread_InitArch (Thread *thr)
 
void Thread_SetupKThread (Thread *thr, void(*f)(), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
 
void Thread_SetupUThread (Thread *thr, uint64_t rip, uint64_t arg)
 
void Thread_SwitchArch (Thread *oldthr, Thread *newthr)
 
void Handle_Init (Process *proc)
 
void Handle_Destroy (Process *proc)
 
uint64_t Handle_Add (Process *proc, Handle *handle)
 
void Handle_Remove (Process *proc, Handle *handle)
 
HandleHandle_Lookup (Process *proc, uint64_t fd)
 
int Copy_In (uintptr_t fromuser, void *tokernel, uintptr_t len)
 
int Copy_Out (void *fromkernel, uintptr_t touser, uintptr_t len)
 
int Copy_StrIn (uintptr_t fromuser, void *tokernel, uintptr_t len)
 
int Copy_StrOut (void *fromkernel, uintptr_t touser, uintptr_t len)
 

Macro Definition Documentation

◆ PROC_STATE_NULL

#define PROC_STATE_NULL   0

Definition at line 61 of file thread.h.

◆ PROC_STATE_READY

#define PROC_STATE_READY   1

Definition at line 62 of file thread.h.

◆ PROC_STATE_ZOMBIE

#define PROC_STATE_ZOMBIE   2

Definition at line 63 of file thread.h.

◆ PROCESS_HANDLE_SLOTS

#define PROCESS_HANDLE_SLOTS   128

Definition at line 58 of file thread.h.

◆ PROCESS_TITLE_LENGTH

#define PROCESS_TITLE_LENGTH   128

Definition at line 59 of file thread.h.

◆ SCHED_STATE_NULL

#define SCHED_STATE_NULL   0

Definition at line 25 of file thread.h.

◆ SCHED_STATE_RUNNABLE

#define SCHED_STATE_RUNNABLE   1

Definition at line 26 of file thread.h.

◆ SCHED_STATE_RUNNING

#define SCHED_STATE_RUNNING   2

Definition at line 27 of file thread.h.

◆ SCHED_STATE_WAITING

#define SCHED_STATE_WAITING   3

Definition at line 28 of file thread.h.

◆ SCHED_STATE_ZOMBIE

#define SCHED_STATE_ZOMBIE   4

Definition at line 29 of file thread.h.

◆ TID_ANY

#define TID_ANY   0xFFFFFFFF

Definition at line 106 of file thread.h.

Typedef Documentation

◆ Process

typedef struct Process Process

Definition at line 13 of file thread.h.

◆ Thread

typedef struct Thread Thread

Definition at line 11 of file thread.h.

Function Documentation

◆ Copy_In()

int Copy_In ( uintptr_t  fromuser,
void *  tokernel,
uintptr_t  len 
)

Copy_In –

Safely copy memory from userspace. Prevents userspace pointers from reading kernel memory.

Side effects: Kernel page fault may have occurred.

Parameters
[in]fromuserUser address to copy from.
[in]tokernelKernel address to copy to.
[in]lenLength of the data to copy.
Return values
EFAULTif the address is invalid or causes a fault.

Definition at line 34 of file copy.c.

35{
36 if (len == 0)
37 return 0;
38
39 // Kernel space
40 if (fromuser >= MEM_USERSPACE_TOP) {
41 kprintf("Copy_In: address exceeds userspace top\n");
42 return EFAULT;
43 }
44
45 // Wrap around
46 if (len > (MEM_USERSPACE_TOP - fromuser)) {
47 kprintf("Copy_In: length exceeds userspace top\n");
48 return EFAULT;
49 }
50
51 return copy_unsafe(tokernel, (void *)fromuser, len);
52}
int copy_unsafe(void *to_addr, void *from_addr, uintptr_t len)
#define EFAULT
Definition: errno.h:13
int kprintf(const char *fmt,...)
Definition: printf.c:210
uint64_t len
Definition: multiboot.h:2
#define MEM_USERSPACE_TOP
Definition: pmap.h:34
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Copy_Out()

int Copy_Out ( void *  fromkernel,
uintptr_t  touser,
uintptr_t  len 
)

Copy_Out –

Safely copy memory to userspace. Prevents userspace pointers from writing kernel memory.

Side effects: Kernel page fault may have occurred.

Parameters
[in]fromkernelKernel address to copy from.
[in]touserUser address to copy to.
[in]lenLength of the data to copy.
Return values
EFAULTif the address is invalid or causes a fault.

Definition at line 70 of file copy.c.

71{
72 if (len == 0)
73 return 0;
74
75 // Kernel space
76 if (touser >= MEM_USERSPACE_TOP) {
77 kprintf("Copy_Out: address exceeds userspace top\n");
78 return EFAULT;
79 }
80
81 // Wrap around
82 if (len > (MEM_USERSPACE_TOP - touser)) {
83 kprintf("Copy_Out: length exceeds userspace top\n");
84 return EFAULT;
85 }
86
87 return copy_unsafe((void *)touser, fromkernel, len);
88}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Copy_StrIn()

int Copy_StrIn ( uintptr_t  fromuser,
void *  tokernel,
uintptr_t  len 
)

Copy_StrIn –

Safely copy a string from userspace. Prevents userspace pointers from reading kernel memory.

Side effects: Kernel page fault may have occurred.

Parameters
[in]fromuserUser address to copy from.
[in]tokernelKernel address to copy to.
[in]lenMaximum string length.
Return values
EFAULTif the address is invalid or causes a fault.

Definition at line 106 of file copy.c.

107{
108 if (len == 0)
109 return 0;
110
111 // Kernel space
112 if (fromuser >= MEM_USERSPACE_TOP) {
113 kprintf("Copy_StrIn: address exceeds userspace top\n");
114 return EFAULT;
115 }
116
117 // Wrap around
118 if (len > (MEM_USERSPACE_TOP - fromuser)) {
119 kprintf("Copy_StrIn: length exceeds userspace top\n");
120 return EFAULT;
121 }
122
123 return copystr_unsafe(tokernel, (void *)fromuser, len);
124}
int copystr_unsafe(void *to_addr, void *from_addr, uintptr_t len)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Copy_StrOut()

int Copy_StrOut ( void *  fromkernel,
uintptr_t  touser,
uintptr_t  len 
)

Copy_StrOut –

Safely copy a string to userspace. Prevents userspace pointers from writing kernel memory.

Side effects: Kernel page fault may have occurred.

Parameters
[in]fromkernelKernel address to copy from.
[in]touserUser address to copy to.
[in]lenMaximum string length.
Return values
EFAULTif the address is invalid or causes a fault.

Definition at line 142 of file copy.c.

143{
144 if (len == 0)
145 return 0;
146
147 // Kernel space
148 if (touser >= MEM_USERSPACE_TOP) {
149 kprintf("Copy_StrOut: address exceeds userspace top\n");
150 return EFAULT;
151 }
152
153 // Wrap around
154 if (len > (MEM_USERSPACE_TOP - touser)) {
155 kprintf("Copy_StrOut: length exceeds userspace top\n");
156 return EFAULT;
157 }
158
159 return copystr_unsafe((void *)touser, fromkernel, len);
160}
Here is the call graph for this function:

◆ Handle_Add()

uint64_t Handle_Add ( Process proc,
Handle handle 
)

Definition at line 47 of file handle.c.

48{
49 int slot;
50
51 handle->fd = proc->nextFD;
52 proc->nextFD++;
53 handle->processId = proc->pid;
54
55 slot = handle->fd % PROCESS_HANDLE_SLOTS;
56
57 TAILQ_INSERT_HEAD(&proc->handles[slot], handle, handleList);
58
59 return handle->fd;
60}
#define PROCESS_HANDLE_SLOTS
Definition: thread.h:58
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:628
uint64_t fd
Definition: handle.h:18
uint64_t processId
Definition: handle.h:20
uint64_t nextFD
Definition: thread.h:91
HandleQueue handles[PROCESS_HANDLE_SLOTS]
Definition: thread.h:92
uint64_t pid
Definition: thread.h:66
Here is the caller graph for this function:

◆ Handle_Destroy()

void Handle_Destroy ( Process proc)

Definition at line 33 of file handle.c.

34{
35 int i;
36 Handle *handle, *handle_tmp;
37
38 for (i = 0; i < PROCESS_HANDLE_SLOTS; i++) {
39 TAILQ_FOREACH_SAFE(handle, &proc->handles[i], handleList, handle_tmp) {
40 TAILQ_REMOVE(&proc->handles[i], handle, handleList);
41 (handle->close)(handle);
42 }
43 }
44}
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:567
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:659
Definition: handle.h:17
int(* close)(Handle *)
Definition: handle.h:26
Here is the caller graph for this function:

◆ Handle_Init()

void Handle_Init ( Process proc)

Definition at line 23 of file handle.c.

24{
25 int i;
26
27 for (i = 0; i < PROCESS_HANDLE_SLOTS; i++) {
28 TAILQ_INIT(&proc->handles[i]);
29 }
30}
#define TAILQ_INIT(head)
Definition: queue.h:597
Here is the caller graph for this function:

◆ Handle_Lookup()

Handle * Handle_Lookup ( Process proc,
uint64_t  fd 
)

Definition at line 71 of file handle.c.

72{
73 int slot = fd % PROCESS_HANDLE_SLOTS;
74 Handle *handle;
75
76 TAILQ_FOREACH(handle, &proc->handles[slot], handleList) {
77 if (handle->fd == fd)
78 return handle;
79 }
80
81 return NULL;
82}
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:557
#define NULL
Definition: stddef.h:6
Here is the caller graph for this function:

◆ Handle_Remove()

void Handle_Remove ( Process proc,
Handle handle 
)

Definition at line 63 of file handle.c.

64{
65 int slot = handle->fd % PROCESS_HANDLE_SLOTS;
66
67 TAILQ_REMOVE(&proc->handles[slot], handle, handleList);
68}

◆ Process_Create()

Process * Process_Create ( Process parent,
const char *  title 
)

Process_Create –

Create a process.

Parameters
[in]parentParent process.
[in]titleProcess title.
Returns
The newly created process.

Definition at line 50 of file process.c.

51{
53
54 if (!proc)
55 return NULL;
56
57 memset(proc, 0, sizeof(*proc));
58
59 proc->pid = nextProcessID++;
60 proc->threads = 0;
61 proc->refCount = 1;
63 TAILQ_INIT(&proc->threadList);
64
65 if (title) {
66 strncpy((char *)&proc->title, title, PROCESS_TITLE_LENGTH);
67 } else {
68 proc->title[0] = '\0';
69 }
70
71 proc->space = PMap_NewAS();
72 if (proc->space == NULL) {
73 Slab_Free(&processSlab, proc);
74 return NULL;
75 }
77
78 Spinlock_Init(&proc->lock, "Process Lock", SPINLOCK_TYPE_NORMAL);
79
80 Semaphore_Init(&proc->zombieSemaphore, 0, "Zombie Semaphore");
81 TAILQ_INIT(&proc->zombieQueue);
82
83 Handle_Init(proc);
84
85 proc->parent = parent;
86 if (parent) {
87 Spinlock_Lock(&parent->lock);
88 TAILQ_INSERT_TAIL(&parent->childrenList, proc, siblingList);
89 Spinlock_Unlock(&parent->lock);
90 }
92 TAILQ_INIT(&proc->zombieProc);
93 Mutex_Init(&proc->zombieProcLock, "Zombie Process Lock");
94 CV_Init(&proc->zombieProcCV, "Zombie Process CV");
95 CV_Init(&proc->zombieProcPCV, "Zombie Process PCV");
96
100
101 return proc;
102}
void CV_Init(CV *cv, const char *name)
Definition: cv.c:25
void Handle_Init(Process *proc)
Definition: handle.c:23
#define PROC_STATE_NULL
Definition: thread.h:61
#define PROCESS_TITLE_LENGTH
Definition: thread.h:59
void Slab_Free(Slab *slab, void *obj)
Definition: slab.c:135
void * Slab_Alloc(Slab *slab) __attribute__((malloc))
Definition: slab.c:105
AS * PMap_NewAS()
Definition: pmap.c:80
#define MEM_USERSPACE_STKBASE
Definition: pmap.h:36
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:641
void Semaphore_Init(Semaphore *sema, int count, const char *name)
void Spinlock_Unlock(Spinlock *lock) __UNLOCK_EX(*lock)
Definition: spinlock.c:109
#define SPINLOCK_TYPE_NORMAL
Definition: spinlock.h:12
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
char * strncpy(char *to, const char *from, size_t len)
Definition: string.c:34
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
Definition: thread.h:65
Spinlock lock
Definition: thread.h:68
uint64_t refCount
Definition: thread.h:73
ProcessQueue zombieProc
Definition: thread.h:81
ThreadQueue threadList
Definition: thread.h:87
uintptr_t ustackNext
Definition: thread.h:71
char title[PROCESS_TITLE_LENGTH]
Definition: thread.h:74
ThreadQueue zombieQueue
Definition: thread.h:89
uint64_t threads
Definition: thread.h:86
Process * parent
Definition: thread.h:78
Semaphore zombieSemaphore
Definition: thread.h:88
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
AS * space
Definition: thread.h:67
void Mutex_Init(Mutex *mtx, const char *name)
Definition: mutex.c:30
ProcessQueue processList
Definition: process.c:30
uint64_t nextProcessID
Definition: process.c:29
Spinlock procLock
Definition: process.c:28
Slab processSlab
Definition: process.c:33
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Process_Dump()

void Process_Dump ( Process proc)

Definition at line 251 of file process.c.

252{
253 const char *stateStrings[] = {
254 "NULL",
255 "READY",
256 "ZOMBIE"
257 };
258
259 kprintf("title %s\n", proc->title);
260 kprintf("pid %llu\n", proc->pid);
261 kprintf("state %s\n", stateStrings[proc->procState]);
262 kprintf("space %016llx\n", proc->space);
263 kprintf("threads %llu\n", proc->threads);
264 kprintf("refCount %d\n", proc->refCount);
265 kprintf("nextFD %llu\n", proc->nextFD);
266}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Process_Lookup()

Process * Process_Lookup ( uint64_t  pid)

Process_Lookup –

Lookup a process by PID and increment its reference count.

Parameters
[in]pidProcess ID to search for.
Return values
NULLNo such process.
Returns
Process that corresponds to the pid.

Definition at line 145 of file process.c.

146{
147 Process *p;
148 Process *proc = NULL;
149
152 if (p->pid == pid) {
154 proc = p;
155 break;
156 }
157 }
159
160 return proc;
161}
void Process_Retain(Process *proc)
Definition: process.c:171
Here is the call graph for this function:

◆ Process_Release()

void Process_Release ( Process proc)

Process_Release –

Decrement the reference count for a given process.

Parameters
procProcess to release a reference of.

Definition at line 185 of file process.c.

186{
187 ASSERT(proc->refCount != 0);
188 if (__sync_fetch_and_sub(&proc->refCount, 1) == 1) {
189 Process_Destroy(proc);
190 }
191}
#define ASSERT(_x)
Definition: kassert.h:8
static void Process_Destroy(Process *proc)
Definition: process.c:113
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Process_Retain()

void Process_Retain ( Process proc)

Process_Retain –

Increment the reference count for a given process.

Parameters
procProcess to retain a reference to.

Definition at line 171 of file process.c.

172{
173 ASSERT(proc->refCount != 0);
174 __sync_fetch_and_add(&proc->refCount, 1);
175}
Here is the caller graph for this function:

◆ Process_Wait()

uint64_t Process_Wait ( Process proc,
uint64_t  pid 
)

Process_Wait –

Wait for a process to exit and then cleanup it's references. If the pid == 0, we wait for any process, otherwise we wait for a specific process.

Parameters
[in]procParent process.
[in]pidOptionally specify the pid of the process to wait on.
Return values
ENOENTProcess ID doesn't exist.
Returns
Exit status of the process that exited or crashed.

Definition at line 206 of file process.c.

207{
208 Thread *thr;
209 Process *p = NULL;
210 uint64_t status;
211
212 // XXXFILLMEIN
213 /*
214 * Dummy waitpid implementation that pretends the
215 * process has already exited. Remove and replace
216 * with the actual implementation from the assignment
217 * description.
218 */
219 /* XXXREMOVE START */
220 ASSERT(pid != 0);
221 return (pid << 16);
222 /* XXXREMOVE END */
223
224 status = (p->pid << 16) | (p->exitCode & 0xff);
225
226 // Release threads
227 Spinlock_Lock(&proc->lock);
228 while (!TAILQ_EMPTY(&p->zombieQueue)) {
229 thr = TAILQ_FIRST(&p->zombieQueue);
230 TAILQ_REMOVE(&p->zombieQueue, thr, schedQueue);
231 Spinlock_Unlock(&proc->lock);
232
233 ASSERT(thr->proc->pid != 1);
234 Thread_Release(thr);
235
236 Spinlock_Lock(&proc->lock);
237 }
238 Spinlock_Unlock(&proc->lock);
239
240 // Release process
242
243 return SYSCALL_PACK(0, status);
244}
void Thread_Release(Thread *thr)
Definition: thread.c:265
#define TAILQ_FIRST(head)
Definition: queue.h:555
#define TAILQ_EMPTY(head)
Definition: queue.h:553
uint64_t exitCode
Definition: thread.h:76
Definition: thread.h:31
struct Process * proc
Definition: thread.h:39
#define SYSCALL_PACK(_errcode, _val)
Definition: syscall.h:55
void Process_Release(Process *proc)
Definition: process.c:185
unsigned long uint64_t
Definition: types.h:13
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Sched_Current()

Thread * Sched_Current ( )

Sched_Current()

Get the currently executing thread. This function retains a reference count and you must release the reference by calling Thread_Release.

Returns
Returns the current thread.

Definition at line 56 of file sched.c.

57{
59
60 Thread *thr = curProc[CPU()];
61 Thread_Retain(thr);
62
64
65 return thr;
66}
#define CPU
Definition: mp.h:7
void Thread_Retain(Thread *thr)
Definition: thread.c:253
Thread * curProc[MAX_CPUS]
Definition: sched.c:41
Spinlock schedLock
Definition: sched.c:29
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Sched_Scheduler()

void Sched_Scheduler ( )

Sched_Scheduler –

Run our round robin scheduler to find the process and switch to it.

Definition at line 189 of file sched.c.

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}
#define SCHED_STATE_RUNNING
Definition: thread.h:27
#define SCHED_STATE_RUNNABLE
Definition: thread.h:26
ThreadQueue runnableQueue
Definition: sched.c:37
static void Sched_Switch(Thread *oldthr, Thread *newthr)
Definition: sched.c:175
uint64_t ctxSwitches
Definition: thread.h:51
int schedState
Definition: thread.h:42
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Sched_SetRunnable()

void Sched_SetRunnable ( Thread thr)

Sched_SetRunnable –

Set the thread to the runnable state and move it from the wait queue if necessary to the runnable queue.

Parameters
[in]thrThread to be set as runnable.

Definition at line 77 of file sched.c.

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}
#define PROC_STATE_READY
Definition: thread.h:62
#define SCHED_STATE_WAITING
Definition: thread.h:28
UnixEpochNS KTime_GetEpochNS()
Definition: ktime.c:194
ThreadQueue waitQueue
Definition: sched.c:33
uint64_t waitTime
Definition: thread.h:54
uint64_t waitStart
Definition: thread.h:55
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Sched_SetWaiting()

void Sched_SetWaiting ( Thread thr)

Sched_SetWaiting –

Set the thread to the waiting state and move it to the wait queue. The thread should be currently running.

Parameters
[in]thrThread to be set as waiting.

Definition at line 104 of file sched.c.

105{
107
109
111 TAILQ_INSERT_TAIL(&waitQueue, thr, schedQueue);
113
115}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Sched_SetZombie()

void Sched_SetZombie ( Thread thr)

Sched_SetZombie –

Set the thread to the zombie state and move it to the parent processes's zombie process queue. The thread should be currently running.

Parameters
[in]thrThread to be set as zombie.

Definition at line 126 of file sched.c.

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}
uint32_t Critical_Level()
Definition: critical.c:45
void CV_Signal(CV *cv)
Definition: cv.c:59
#define PROC_STATE_ZOMBIE
Definition: thread.h:63
#define SCHED_STATE_ZOMBIE
Definition: thread.h:29
void Mutex_Unlock(Mutex *mtx)
Definition: mutex.c:83
void Mutex_Lock(Mutex *mtx)
Definition: mutex.c:52
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TAILQ_HEAD() [1/2]

typedef TAILQ_HEAD ( ProcessQueue  ,
Process   
)

◆ TAILQ_HEAD() [2/2]

typedef TAILQ_HEAD ( ThreadQueue  ,
Thread   
)

◆ Thread_Create()

Thread * Thread_Create ( Process proc)

Definition at line 96 of file thread.c.

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}
void Thread_InitArch(Thread *thr)
Definition: thread.c:20
void Process_Retain(Process *proc)
Definition: process.c:171
#define SCHED_STATE_NULL
Definition: thread.h:25
Slab threadSlab
Definition: thread.c:48
void * PAlloc_AllocPage()
Definition: palloc.c:188
#define MEM_USERSPACE_STKLEN
Definition: pmap.h:37
uint64_t nextThreadID
Definition: thread.h:70
uint64_t refCount
Definition: thread.h:37
uintptr_t ustack
Definition: thread.h:35
AS * space
Definition: thread.h:33
KTimerEvent * timerEvt
Definition: thread.h:44
uint64_t tid
Definition: thread.h:36
uintptr_t kstack
Definition: thread.h:34
uint64_t uintptr_t
Definition: types.h:16
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_Dump()

void Thread_Dump ( Thread thr)

Definition at line 328 of file thread.c.

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}
void Process_Dump(Process *proc)
Definition: process.c:251
uint64_t kernTime
Definition: thread.h:53
uint64_t userTime
Definition: thread.h:52
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_Init()

void Thread_Init ( )

Definition at line 53 of file thread.c.

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}
Process * Process_Create(Process *parent, const char *title)
Definition: process.c:50
ProcessQueue processList
Definition: process.c:30
Thread * Thread_Create(Process *proc)
Definition: thread.c:96
uint64_t nextProcessID
Definition: process.c:29
ThreadQueue runnableQueue
Definition: sched.c:37
Thread * curProc[MAX_CPUS]
Definition: sched.c:41
void Handle_GlobalInit()
Definition: handle.c:15
Spinlock procLock
Definition: process.c:28
Spinlock schedLock
Definition: sched.c:29
Slab processSlab
Definition: process.c:33
Process * kernelProcess
Definition: thread.c:45
ThreadQueue waitQueue
Definition: sched.c:33
void Slab_Init(Slab *slab, const char *name, uintptr_t objsz, uintptr_t align)
#define SPINLOCK_TYPE_RECURSIVE
Definition: spinlock.h:13
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_InitAP()

void Thread_InitAP ( )

Definition at line 79 of file thread.c.

80{
82
84
85 //PAlloc_Release((void *)thr->kstack);
86 //thr->kstack = 0;
87
88 curProc[CPU()] = apthr;
89}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_InitArch()

void Thread_InitArch ( Thread thr)

Definition at line 20 of file thread.c.

21{
22 thr->arch.useFP = true;
23}
bool useFP
Definition: thread.h:21
ThreadArch arch
Definition: thread.h:32
Here is the caller graph for this function:

◆ Thread_KThreadCreate()

Thread * Thread_KThreadCreate ( void(*)(void *)  f,
void *  arg 
)

Definition at line 136 of file thread.c.

137{
139 if (!thr)
140 return NULL;
141
142 Thread_SetupKThread(thr, f, (uintptr_t)arg, 0, 0);
143
144 return thr;
145}
void Thread_SetupKThread(Thread *thr, void(*f)(), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
Definition: thread.c:26
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_Lookup()

Thread * Thread_Lookup ( Process proc,
uint64_t  tid 
)

Thread_Lookup –

Lookup a thread by TID and increment its reference count.

Parameters
[in]procProcess within which to find a specific thread.
[in]tidThread ID of the thread to find.
Return values
NULLif the thread isn't found.

Definition at line 229 of file thread.c.

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}
void Thread_Retain(Thread *thr)
Definition: thread.c:253
Here is the call graph for this function:

◆ Thread_Release()

void Thread_Release ( Thread thr)

Thread_Release –

Decrement the reference count for a given thread.

Definition at line 265 of file thread.c.

266{
267 ASSERT(thr->refCount != 0);
268 if (__sync_fetch_and_sub(&thr->refCount, 1) == 1) {
269 Thread_Destroy(thr);
270 }
271}
static void Thread_Destroy(Thread *thr)
Definition: thread.c:195
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_Retain()

void Thread_Retain ( Thread thr)

Thread_Retain –

Increment the reference count for a given thread.

Definition at line 253 of file thread.c.

254{
255 ASSERT(thr->refCount != 0);
256 __sync_fetch_and_add(&thr->refCount, 1);
257}
Here is the caller graph for this function:

◆ Thread_SetupKThread()

void Thread_SetupKThread ( Thread thr,
void(*)()  f,
uintptr_t  arg1,
uintptr_t  arg2,
uintptr_t  arg3 
)

Definition at line 26 of file thread.c.

28{
29 // Initialize stack
30 uint64_t stacktop = thr->kstack + PGSIZE;
32 TrapFrame *tf;
33
34 tf = (TrapFrame *)(stacktop - sizeof(*tf));
35 sf = (ThreadArchStackFrame *)(stacktop - sizeof(*tf) - sizeof(*sf));
36 thr->arch.rsp = (uint64_t)sf;
37
38 memset(tf, 0, sizeof(*tf));
39 memset(sf, 0, sizeof(*sf));
40
41 // Setup thread exit function on stack
42
44 sf->rdi = (uint64_t)tf;
45
46 tf->ds = 0;
47 tf->ss = 0; //SEL_KDS;
48 tf->rsp = stacktop;
49 tf->cs = SEL_KCS;
50 tf->rip = (uint64_t)f;
51 tf->rdi = (uint64_t)arg1;
52 tf->rsi = (uint64_t)arg2;
53 tf->rdx = (uint64_t)arg3;
54 tf->rflags = RFLAGS_IF;
55}
uint64_t rsp
Definition: thread.h:22
uint64_t rip
Definition: thread.h:16
uint64_t rdi
Definition: thread.h:14
void ThreadKThreadEntry(TrapFrame *tf)
Definition: thread.c:314
#define RFLAGS_IF
Definition: amd64.h:180
#define SEL_KCS
Definition: amd64.h:80
#define PGSIZE
Definition: malloc.c:21
uint16_t cs
Definition: trap.h:73
uint64_t rsi
Definition: trap.h:62
uint16_t ss
Definition: trap.h:79
uint64_t rsp
Definition: trap.h:78
uint64_t rip
Definition: trap.h:72
uint64_t rdi
Definition: trap.h:61
uint64_t rflags
Definition: trap.h:77
uint64_t ds
Definition: trap.h:66
uint64_t rdx
Definition: trap.h:63
Definition: trap.h:51
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_SetupUThread()

void Thread_SetupUThread ( Thread thr,
uint64_t  rip,
uint64_t  arg 
)

Definition at line 75 of file thread.c.

76{
78 thr->ustack, arg);
79}
static void ThreadEnterUserLevelCB(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
Definition: thread.c:58
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_SwitchArch()

void Thread_SwitchArch ( Thread oldthr,
Thread newthr 
)

Definition at line 84 of file thread.c.

85{
86 /*
87 * Save and restore floating point and vector CPU state using the fxsave
88 * and fxrstor instructions.
89 */
90 if (oldthr->arch.useFP)
91 {
92 fxsave(&oldthr->arch.xsa);
93 }
94
95 if (newthr->arch.useFP)
96 {
97 fxrstor(&newthr->arch.xsa);
98 }
99
100 clts();
101
102 // Jump to trapframe
103 switchstack(&oldthr->arch.rsp, newthr->arch.rsp);
104
105 // Set new RSP0
106 TSS[CPU()].rsp0 = oldthr->kstack + 4096;
107}
XSAVEArea xsa
Definition: thread.h:20
void switchstack(uint64_t *oldrsp, uint64_t rsp)
TaskStateSegment64 TSS[MAX_CPUS]
Definition: machine.c:40
uint64_t rsp0
Definition: amd64.h:108
static INLINE void fxrstor(struct XSAVEArea *xsa)
Definition: amd64op.h:386
static INLINE void clts()
Definition: amd64op.h:372
static INLINE void fxsave(struct XSAVEArea *xsa)
Definition: amd64op.h:377
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_UThreadCreate()

Thread * Thread_UThreadCreate ( Thread oldThr,
uint64_t  rip,
uint64_t  arg 
)

Definition at line 148 of file thread.c.

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}
void Thread_SetupUThread(Thread *thr, uintptr_t rip, uintptr_t arg)
Definition: thread.c:75
#define PTE_W
Definition: amd64.h:36
bool PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags)
Definition: pmap.c:423
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Thread_Wait()

uint64_t Thread_Wait ( Thread thr,
uint64_t  tid 
)

Thread_Wait –

Wait for any thread (tid == TID_ANY) or a specific thread.

Definition at line 279 of file thread.c.

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}
#define EAGAIN
Definition: errno.h:19
#define TID_ANY
Definition: thread.h:106
void Thread_Release(Thread *thr)
Definition: thread.c:265
uintptr_t exitValue
Definition: thread.h:45
Here is the call graph for this function:
Here is the caller graph for this function: