summaryrefslogtreecommitdiff
path: root/user
diff options
context:
space:
mode:
authorSanjit Bhat <[email protected]>2023-09-13 02:01:38 -0400
committerSanjit Bhat <[email protected]>2023-09-13 02:01:38 -0400
commit87470490676ee6dc087e3ebe2a3ce3cfbd4afbd9 (patch)
tree64398d88609ac3b9fc045071ae6703269c97ce26 /user
parent74c1eba516fdb0ec1a17b16be7e76613ccba92bf (diff)
downloadxv6-labs-87470490676ee6dc087e3ebe2a3ce3cfbd4afbd9.tar.gz
xv6-labs-87470490676ee6dc087e3ebe2a3ce3cfbd4afbd9.tar.bz2
xv6-labs-87470490676ee6dc087e3ebe2a3ce3cfbd4afbd9.zip
release lab thread
Diffstat (limited to 'user')
-rw-r--r--user/uthread.c162
-rw-r--r--user/uthread_switch.S11
2 files changed, 173 insertions, 0 deletions
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);
+}
diff --git a/user/uthread_switch.S b/user/uthread_switch.S
new file mode 100644
index 0000000..5defb12
--- /dev/null
+++ b/user/uthread_switch.S
@@ -0,0 +1,11 @@
+ .text
+
+ /*
+ * save the old thread's registers,
+ * restore the new thread's registers.
+ */
+
+ .globl thread_switch
+thread_switch:
+ /* YOUR CODE HERE */
+ ret /* return to ra */