diff options
Diffstat (limited to 'user')
| -rw-r--r-- | user/uthread.c | 162 | ||||
| -rw-r--r-- | user/uthread_switch.S | 11 | 
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 */ | 
