这个实验我只是做了 Uthread 。后面关于 pthread 部分并没有做,一来是懒,二来现在 Pthread 用的不多了,主要还是用 OpenMP 来进行多线程编程。
thread 数据结构:
struct thread {  | |
char stack[STACK_SIZE]; /* the thread's stack */  | |
int state; /* FREE, RUNNING, RUNNABLE */  | |
char context[4096]; //for context save. 这里的 context 实际上是 char * 类型,也就是 4096 字节的地址空间。  | |
};  | 
create_thread :
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 | |
*(uint64*)(t->context) = (uint64)func; // 这个就是使用 func  | |
*(uint64*)(t->context + 8) = (uint64)(t->stack+STACK_SIZE);  | |
} | 
进程调度 :
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;  | |
thread_switch((uint64)t->context, (uint64)current_thread->context);  | |
    /* YOUR CODE HERE | |
* Invoke thread_switch to switch from t to next_thread:  | |
* thread_switch(??, ??);  | |
*/  | |
} else  | |
next_thread = 0;  | |
} | 
切换函数 :
	.globl thread_switch
thread_switch:
	/* YOUR CODE HERE */
        sd ra, 0(a0)
        sd sp, 8(a0)
        sd s0, 16(a0)
        sd s1, 24(a0)
        sd s2, 32(a0)
        sd s3, 40(a0)
        sd s4, 48(a0)
        sd s5, 56(a0)
        sd s6, 64(a0)
        sd s7, 72(a0)
        sd s8, 80(a0)
        sd s9, 88(a0)
        sd s10, 96(a0)
        sd s11, 104(a0)
        ld ra, 0(a1)
        ld sp, 8(a1)
        ld s0, 16(a1)
        ld s1, 24(a1)
        ld s2, 32(a1)
        ld s3, 40(a1)
        ld s4, 48(a1)
        ld s5, 56(a1)
        ld s6, 64(a1)
        ld s7, 72(a1)
        ld s8, 80(a1)
        ld s9, 88(a1)
        ld s10, 96(a1)
        ld s11, 104(a1)
	ret    /* return to ra */
主要有意思的点就是,create 的时候,自己制定了 ra 和 sp 两个寄存器的数据。这种直接用指针进行操作内存的方式,不得不感叹真的自由度高。