From 87470490676ee6dc087e3ebe2a3ce3cfbd4afbd9 Mon Sep 17 00:00:00 2001 From: Sanjit Bhat Date: Wed, 13 Sep 2023 02:01:38 -0400 Subject: release lab thread --- user/uthread.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 user/uthread.c (limited to 'user/uthread.c') diff --git a/user/uthread.c b/user/uthread.c new file mode 100644 index 0000000..06349f5 --- /dev/null +++ b/user/uthread.c @@ -0,0 +1,162 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +/* Possible states of a thread: */ +#define FREE 0x0 +#define RUNNING 0x1 +#define RUNNABLE 0x2 + +#define STACK_SIZE 8192 +#define MAX_THREAD 4 + + +struct thread { + char stack[STACK_SIZE]; /* the thread's stack */ + int state; /* FREE, RUNNING, RUNNABLE */ +}; +struct thread all_thread[MAX_THREAD]; +struct thread *current_thread; +extern void thread_switch(uint64, uint64); + +void +thread_init(void) +{ + // main() is thread 0, which will make the first invocation to + // thread_schedule(). it needs a stack so that the first thread_switch() can + // save thread 0's state. thread_schedule() won't run the main thread ever + // again, because its state is set to RUNNING, and thread_schedule() selects + // a RUNNABLE thread. + current_thread = &all_thread[0]; + current_thread->state = RUNNING; +} + +void +thread_schedule(void) +{ + struct thread *t, *next_thread; + + /* Find another runnable thread. */ + next_thread = 0; + t = current_thread + 1; + for(int i = 0; i < MAX_THREAD; i++){ + if(t >= all_thread + MAX_THREAD) + t = all_thread; + if(t->state == RUNNABLE) { + next_thread = t; + break; + } + t = t + 1; + } + + if (next_thread == 0) { + printf("thread_schedule: no runnable threads\n"); + exit(-1); + } + + if (current_thread != next_thread) { /* switch threads? */ + next_thread->state = RUNNING; + t = current_thread; + current_thread = next_thread; + /* YOUR CODE HERE + * Invoke thread_switch to switch from t to next_thread: + * thread_switch(??, ??); + */ + } else + next_thread = 0; +} + +void +thread_create(void (*func)()) +{ + struct thread *t; + + for (t = all_thread; t < all_thread + MAX_THREAD; t++) { + if (t->state == FREE) break; + } + t->state = RUNNABLE; + // YOUR CODE HERE +} + +void +thread_yield(void) +{ + current_thread->state = RUNNABLE; + thread_schedule(); +} + +volatile int a_started, b_started, c_started; +volatile int a_n, b_n, c_n; + +void +thread_a(void) +{ + int i; + printf("thread_a started\n"); + a_started = 1; + while(b_started == 0 || c_started == 0) + thread_yield(); + + for (i = 0; i < 100; i++) { + printf("thread_a %d\n", i); + a_n += 1; + thread_yield(); + } + printf("thread_a: exit after %d\n", a_n); + + current_thread->state = FREE; + thread_schedule(); +} + +void +thread_b(void) +{ + int i; + printf("thread_b started\n"); + b_started = 1; + while(a_started == 0 || c_started == 0) + thread_yield(); + + for (i = 0; i < 100; i++) { + printf("thread_b %d\n", i); + b_n += 1; + thread_yield(); + } + printf("thread_b: exit after %d\n", b_n); + + current_thread->state = FREE; + thread_schedule(); +} + +void +thread_c(void) +{ + int i; + printf("thread_c started\n"); + c_started = 1; + while(a_started == 0 || b_started == 0) + thread_yield(); + + for (i = 0; i < 100; i++) { + printf("thread_c %d\n", i); + c_n += 1; + thread_yield(); + } + printf("thread_c: exit after %d\n", c_n); + + current_thread->state = FREE; + thread_schedule(); +} + +int +main(int argc, char *argv[]) +{ + a_started = b_started = c_started = 0; + a_n = b_n = c_n = 0; + thread_init(); + thread_create(thread_a); + thread_create(thread_b); + thread_create(thread_c); + thread_schedule(); + exit(0); +} -- cgit v1.2.3 From b43a5b2b12d20ec0aa8de26dd273558b9bc4522b Mon Sep 17 00:00:00 2001 From: Sanjit Bhat Date: Tue, 3 Oct 2023 15:42:07 -0500 Subject: thread0 state free upon completion --- user/uthread.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'user/uthread.c') diff --git a/user/uthread.c b/user/uthread.c index 06349f5..18b773d 100644 --- a/user/uthread.c +++ b/user/uthread.c @@ -23,10 +23,8 @@ void thread_init(void) { // main() is thread 0, which will make the first invocation to - // thread_schedule(). it needs a stack so that the first thread_switch() can - // save thread 0's state. thread_schedule() won't run the main thread ever - // again, because its state is set to RUNNING, and thread_schedule() selects - // a RUNNABLE thread. + // thread_schedule(). It needs a stack so that the first thread_switch() can + // save thread 0's state. current_thread = &all_thread[0]; current_thread->state = RUNNING; } @@ -157,6 +155,7 @@ main(int argc, char *argv[]) thread_create(thread_a); thread_create(thread_b); thread_create(thread_c); + current_thread->state = FREE; thread_schedule(); exit(0); } -- cgit v1.2.3 From edd523ffcb39c1c57944796fabfc71c70a10ce2e Mon Sep 17 00:00:00 2001 From: Mole Shang <135e2@135e2.dev> Date: Fri, 16 Feb 2024 11:29:36 +0800 Subject: lab thread: finish --- user/uthread.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'user/uthread.c') diff --git a/user/uthread.c b/user/uthread.c index 18b773d..7641d77 100644 --- a/user/uthread.c +++ b/user/uthread.c @@ -11,9 +11,30 @@ #define MAX_THREAD 4 +// Saved registers for kernel context switches. +struct context { + uint64 ra; + uint64 sp; + + // callee-saved + uint64 s0; + uint64 s1; + uint64 s2; + uint64 s3; + uint64 s4; + uint64 s5; + uint64 s6; + uint64 s7; + uint64 s8; + uint64 s9; + uint64 s10; + uint64 s11; +}; + struct thread { char stack[STACK_SIZE]; /* the thread's stack */ int state; /* FREE, RUNNING, RUNNABLE */ + struct context context; /* saved registers to switch thru threads */ }; struct thread all_thread[MAX_THREAD]; struct thread *current_thread; @@ -56,10 +77,8 @@ thread_schedule(void) next_thread->state = RUNNING; t = current_thread; current_thread = next_thread; - /* YOUR CODE HERE - * Invoke thread_switch to switch from t to next_thread: - * thread_switch(??, ??); - */ + // Invoke thread_switch to switch from t to next_thread: + thread_switch((uint64)&t->context, (uint64)&next_thread->context); } else next_thread = 0; } @@ -73,7 +92,11 @@ thread_create(void (*func)()) if (t->state == FREE) break; } t->state = RUNNABLE; - // YOUR CODE HERE + // Set up new context to start executing at func + memset(&t->context, 0, sizeof(struct context)); + t->context.ra = (uint64)func; + // stack grows downward, set sp at the highest stack address in out thread + t->context.sp = (uint64)t->stack + STACK_SIZE; } void -- cgit v1.2.3