1 2 3  _uthread: uthread.o uthread_switch.o $(LD)$(LDFLAGS) -N -e main -Ttext 0 -o _uthread uthread.o uthread_switch.o $(ULIB)$(OBJDUMP) -S _uthread > uthread.asm 

 1 2 3  $uthread lapicid 1: panic: remap 80106967 80105911 801056fc 0 0 0 0 0 0 0 整个作业是要实现 uthread_switch.S 即线程切换的过程： The job of uthread_switch is to save the current thread state into the structure pointed to by current_thread, restore next_thread’s state, and make current_thread point to where next_thread was pointing to, so that when uthread_switch returns next_thread is running and is the current_thread. 线程结构如下：  1 2 3 4 5  struct thread { int sp; /* saved stack pointer */ char stack[STACK_SIZE]; /* the thread's stack */ int state; /* FREE, RUNNING, RUNNABLE */ }; 关于具体的压栈可以参考 thread_create()   1 2 3 4 5 6 7 8 9 10 11 12 13 14  void thread_create(void (*func)()) { thread_p t; for (t = all_thread; t < all_thread + MAX_THREAD; t++) { if (t->state == FREE) break; } t->sp = (int) (t->stack + STACK_SIZE); // set sp to the top of the stack t->sp -= 4; // space for return address * (int *) (t->sp) = (int)func; // push return address on stack t->sp -= 32; // space for registers that thread_switch expects t->state = RUNNABLE; } 上面的 32 byte 用于 pushalpopal ，再上面就是线程对应的函数 struct thread 的内存分布   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  -------------------- | 4 bytes for state| -------------------- | stack size bytes | | for stack | -------------------- | 4 bytes for sp | -------------------- <--- current_thread ...... ...... -------------------- | 4 bytes for state| -------------------- | stack size bytes | | for stack | -------------------- | 4 bytes for sp | -------------------- <--- next_thread 整个 uthread_switch() 实现如下   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  thread_switch: /* YOUR CODE HERE */ /* save the current thread state into the structure pointed to by current_thread */ pushal movl current_thread, %eax movl %esp, (%eax) /* restore next_thread's state */ movl next_thread, %eax /* make current_thread point to where next_thread was pointing to */ movl %eax, current_thread movl (%eax), %esp /* clear next_thread */ movl$0x0, next_thread /* pop return address from stack */ popal ret

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  static void thread_schedule(void) { thread_p t; /* Find another runnable thread. */ next_thread = 0; for (t = all_thread; t < all_thread + MAX_THREAD; t++) { if (t->state == RUNNABLE && t != current_thread) { next_thread = t; break; } } if (t >= all_thread + MAX_THREAD && current_thread->state == RUNNABLE) { /* The current thread is the only runnable thread; run it. */ next_thread = current_thread; } if (next_thread == 0) { printf(2, "thread_schedule: no runnable threads\n"); exit(); } if (current_thread != next_thread) { /* switch threads? */ next_thread->state = RUNNING; thread_switch(); } else next_thread = 0; }