├── .gitignore ├── Readme.md ├── v1 ├── main ├── main.c └── switch.s ├── v2 ├── Makefile ├── main.c └── switch.s ├── v3 ├── Makefile ├── main.c ├── sched.c ├── switch.s ├── test.c ├── thread.c └── thread.h ├── v4 ├── Makefile ├── a.out ├── main.c ├── sched.c ├── switch.s ├── test.c ├── thread.c └── thread.h └── v5 ├── .gitignore ├── Makefile ├── main.c ├── sched.c ├── switch.s ├── test.c ├── thread.c └── thread.h /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | a.out 3 | *.swp 4 | *~ 5 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # 线程切换与线程调度原理 2 | 3 | - v1 是切换原理 4 | - v2 是封装 thread_create 5 | - v3 是修改调度函数 6 | - v4 是分模块,并添加 mysleep 等 7 | - v5 添加了时钟,线程有自己的时间片。调度代码参考了 linux 0.11 8 | 9 | # chat 地址 10 | 11 | 地址:https://gitbook.cn/gitchat/activity/5c83b0e7066b712da9b0595f 12 | -------------------------------------------------------------------------------- /v1/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanallen/MyThread/441456848f0e06722392cb798c2ff3c895e1fd71/v1/main -------------------------------------------------------------------------------- /v1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int task[3] = {0, 0, 0}; 4 | int cur = 0; 5 | void switch_to(int n); 6 | 7 | void fun1() { 8 | while(1) { 9 | printf("hello, I'm fun1\n"); 10 | sleep(1); 11 | // 强制切换到线程 2 12 | switch_to(2); 13 | } 14 | } 15 | 16 | void fun2() { 17 | while(1) { 18 | printf("hello, I'm fun2\n"); 19 | sleep(1); 20 | // 强制切换到线程 1 21 | switch_to(1); 22 | } 23 | } 24 | 25 | // 线程启动函数 26 | void start(int n) { 27 | if (n == 1) fun1(); 28 | else if(n == 2) fun2(); 29 | } 30 | 31 | int main() { 32 | int stack1[1024] = {0}; 33 | int stack2[1024] = {0}; 34 | task[1] = (int)(stack1+1013); 35 | task[2] = (int)(stack2+1013); 36 | 37 | // 创建 fun1 线程 38 | // 初始 switch_to 函数栈帧 39 | stack1[1013] = 7; // eflags 40 | stack1[1014] = 6; // eax 41 | stack1[1015] = 5; // edx 42 | stack1[1016] = 4; // ecx 43 | stack1[1017] = 3; // ebx 44 | stack1[1018] = 2; // esi 45 | stack1[1019] = 1; // edi 46 | stack1[1020] = 0; // old ebp 47 | stack1[1021] = (int)start; // ret to start 48 | // start 函数栈帧,刚进入 start 函数的样子 49 | stack1[1022] = 100;// ret to unknown,如果 start 执行结束,表明线程结束 50 | stack1[1023] = 1; // start 的参数 51 | 52 | // 创建 fun2 线程 53 | // 初始 switch_to 函数栈帧 54 | stack2[1013] = 7; // eflags 55 | stack2[1014] = 6; // eax 56 | stack2[1015] = 5; // edx 57 | stack2[1016] = 4; // ecx 58 | stack2[1017] = 3; // ebx 59 | stack2[1018] = 2; // esi 60 | stack2[1019] = 1; // edi 61 | stack2[1020] = 0; // old ebp 62 | stack2[1021] = (int)start; // ret to start 63 | // start 函数栈帧,刚进入 start 函数的样子 64 | stack2[1022] = 100;// ret to unknown,如果 start 执行结束,表明线程结束 65 | stack2[1023] = 2; // start 的参数 66 | 67 | switch_to(1); 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /v1/switch.s: -------------------------------------------------------------------------------- 1 | /*void switch_to(int n)*/ 2 | 3 | .section .text 4 | .global switch_to 5 | switch_to: 6 | push %ebp 7 | mov %esp, %ebp /* 更改栈帧,以便寻参 */ 8 | 9 | /* 保存现场 */ 10 | push %edi 11 | push %esi 12 | push %ebx 13 | push %edx 14 | push %ecx 15 | push %eax 16 | pushfl 17 | 18 | /* 准备切换栈 */ 19 | mov cur, %eax /* 保存当前 esp */ 20 | mov %esp, task(,%eax,4) 21 | mov 8(%ebp), %eax /* 取下一个线程 id */ 22 | mov %eax, cur /* 将 cur 重置为下一个线程 id */ 23 | mov task(,%eax,4), %esp /* 切换到下一个线程的栈 */ 24 | 25 | /* 恢复现场, 到这里,已经进入另一个线程环境了,本质是 esp 改变 */ 26 | popfl 27 | popl %eax 28 | popl %edx 29 | popl %ecx 30 | popl %ebx 31 | popl %esi 32 | popl %edi 33 | 34 | popl %ebp 35 | ret 36 | 37 | 38 | -------------------------------------------------------------------------------- /v2/Makefile: -------------------------------------------------------------------------------- 1 | main:main.c switch.s 2 | gcc main.c switch.s -o main 3 | -------------------------------------------------------------------------------- /v2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NR_TASKS 16 5 | #define STACK_SIZE 1024 6 | 7 | struct task_struct { 8 | int id; 9 | void (*th_fn)(); 10 | int esp; // 保存 esp 11 | int stack[STACK_SIZE]; 12 | }; 13 | 14 | static struct task_struct init_task = {0, NULL, 0, {0}}; 15 | 16 | struct task_struct *current = &init_task; 17 | 18 | struct task_struct *task[NR_TASKS] = {&init_task,}; 19 | 20 | void switch_to(struct task_struct *next); 21 | 22 | struct task_struct *pick() { 23 | int current_id = current->id; 24 | int i = current_id; 25 | 26 | struct task_struct *next = NULL; 27 | 28 | while(1) { 29 | i = (i + 1) % NR_TASKS; 30 | 31 | if (task[i]) { 32 | next = task[i]; 33 | break; 34 | } 35 | } 36 | 37 | return next; 38 | } 39 | 40 | void fun1() { 41 | while(1) { 42 | printf("hello, I'm fun1\n"); 43 | sleep(1); 44 | struct task_struct *next = pick(); 45 | if (next) { 46 | switch_to(next); 47 | } 48 | } 49 | } 50 | 51 | void fun2() { 52 | while(1) { 53 | printf("hello, I'm fun2\n"); 54 | sleep(1); 55 | struct task_struct *next = pick(); 56 | if (next) { 57 | switch_to(next); 58 | } 59 | } 60 | } 61 | 62 | void fun3() { 63 | int i = 2; 64 | while(i--) { 65 | printf("hello, I'm fun3\n"); 66 | sleep(1); 67 | struct task_struct *next = pick(); 68 | if (next) { 69 | switch_to(next); 70 | } 71 | } 72 | } 73 | 74 | // 线程启动函数 75 | void start(struct task_struct *tsk) { 76 | tsk->th_fn(); 77 | task[tsk->id] = NULL; 78 | struct task_struct *next = pick(); 79 | if (next) { 80 | switch_to(next); 81 | } 82 | } 83 | 84 | int thread_create(int *tid, void (*start_routine)()) { 85 | int id = -1; 86 | struct task_struct *tsk = (struct task_struct*)malloc(sizeof(struct task_struct)); 87 | 88 | while(++id < NR_TASKS && task[id]); 89 | 90 | if (id == NR_TASKS) return -1; 91 | 92 | task[id] = tsk; 93 | 94 | if (tid) *tid = id; 95 | 96 | tsk->id = id; 97 | tsk->th_fn = start_routine; 98 | int *stack = tsk->stack; // 栈顶界限 99 | tsk->esp = (int)(stack+STACK_SIZE-11); 100 | 101 | // 初始 switch_to 函数栈帧 102 | stack[STACK_SIZE-11] = 7; // eflags 103 | stack[STACK_SIZE-10] = 6; // eax 104 | stack[STACK_SIZE-9] = 5; // edx 105 | stack[STACK_SIZE-8] = 4; // ecx 106 | stack[STACK_SIZE-7] = 3; // ebx 107 | stack[STACK_SIZE-6] = 2; // esi 108 | stack[STACK_SIZE-5] = 1; // edi 109 | stack[STACK_SIZE-4] = 0; // old ebp 110 | stack[STACK_SIZE-3] = (int)start; // ret to start 111 | // start 函数栈帧,刚进入 start 函数的样子 112 | stack[STACK_SIZE-2] = 100;// ret to unknown,如果 start 执行结束,表明线程结束 113 | stack[STACK_SIZE-1] = (int)tsk; // start 的参数 114 | 115 | return 0; 116 | } 117 | 118 | int main() { 119 | 120 | int tid1, tid2, tid3; 121 | thread_create(&tid1, fun1); 122 | printf("create thread %d\n", tid1); 123 | thread_create(&tid2, fun2); 124 | printf("create thread %d\n", tid2); 125 | thread_create(&tid3, fun3); 126 | printf("create thread %d\n", tid3); 127 | 128 | int i = 5; 129 | while(i--) { 130 | printf("hello, I'm main\n"); 131 | sleep(1); 132 | struct task_struct *next = pick(); 133 | if (next) { 134 | switch_to(next); 135 | } 136 | } 137 | } 138 | 139 | 140 | -------------------------------------------------------------------------------- /v2/switch.s: -------------------------------------------------------------------------------- 1 | /*void switch_to(struct task_struct* next)*/ 2 | 3 | .section .text 4 | .global switch_to 5 | switch_to: 6 | push %ebp 7 | mov %esp, %ebp /* 更改栈帧,以便寻参 */ 8 | 9 | /* 保存现场 */ 10 | push %edi 11 | push %esi 12 | push %ebx 13 | push %edx 14 | push %ecx 15 | push %eax 16 | pushfl 17 | 18 | /* 准备切换栈 */ 19 | mov current, %eax /* 保存当前 esp, eax 是 current 基址 */ 20 | mov %esp, 8(%eax) 21 | mov 8(%ebp), %eax /* 取下一个线程结构体基址*/ 22 | mov %eax, current /* 更新 current */ 23 | mov 8(%eax), %esp /* 切换到下一个线程的栈 */ 24 | 25 | /* 恢复现场, 到这里,已经进入另一个线程环境了,本质是 esp 改变 */ 26 | popfl 27 | popl %eax 28 | popl %edx 29 | popl %ecx 30 | popl %ebx 31 | popl %esi 32 | popl %edi 33 | 34 | popl %ebp 35 | ret 36 | -------------------------------------------------------------------------------- /v3/Makefile: -------------------------------------------------------------------------------- 1 | main:main.c thread.c thread.h sched.c switch.s 2 | gcc -g main.c thread.c sched.c switch.s -o main 3 | -------------------------------------------------------------------------------- /v3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "thread.h" 4 | 5 | void schedule(); 6 | 7 | void fun1() { 8 | while(1) { 9 | printf("hello, I'm fun1\n"); 10 | sleep(1); 11 | schedule(); 12 | } 13 | } 14 | 15 | void fun2() { 16 | while(1) { 17 | printf("hello, I'm fun2\n"); 18 | sleep(1); 19 | schedule(); 20 | } 21 | } 22 | 23 | void fun3() { 24 | int i = 2; 25 | while(i--) { 26 | printf("hello, I'm fun3\n"); 27 | sleep(1); 28 | schedule(); 29 | } 30 | } 31 | 32 | int main() { 33 | 34 | int tid1, tid2, tid3; 35 | thread_create(&tid1, fun1); 36 | printf("create thread %d\n", tid1); 37 | thread_create(&tid2, fun2); 38 | printf("create thread %d\n", tid2); 39 | thread_create(&tid3, fun3); 40 | printf("create thread %d\n", tid3); 41 | 42 | int i = 5; 43 | while(i--) { 44 | printf("hello, I'm main\n"); 45 | sleep(1); 46 | schedule(); 47 | } 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /v3/sched.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include 3 | #include 4 | 5 | extern struct task_struct *current; 6 | extern struct task_struct *task[NR_TASKS]; 7 | 8 | void switch_to(struct task_struct *next); 9 | 10 | static struct task_struct *pick() { 11 | int current_id = current->id; 12 | int i = current_id; 13 | 14 | struct task_struct *next = NULL; 15 | 16 | while(1) { 17 | i = (i + 1) % NR_TASKS; 18 | if (task[i]) { 19 | next = task[i]; 20 | break; 21 | } 22 | } 23 | 24 | return next; 25 | } 26 | 27 | 28 | 29 | void schedule() { 30 | struct task_struct *next = pick(); 31 | if (next) { 32 | switch_to(next); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /v3/switch.s: -------------------------------------------------------------------------------- 1 | /*void switch_to(struct task_struct *next)*/ 2 | 3 | .section .text 4 | .global switch_to 5 | switch_to: 6 | push %ebp 7 | mov %esp, %ebp /* 更改栈帧,以便寻参 */ 8 | 9 | /* 保存现场 */ 10 | push %edi 11 | push %esi 12 | push %ebx 13 | push %edx 14 | push %ecx 15 | push %eax 16 | pushfl 17 | 18 | /* 准备切换栈 */ 19 | mov current, %eax /* 取 current 基址放到 eax */ 20 | mov %esp, 8(%eax) /* 保存当前 esp 到线程结构体 */ 21 | mov 8(%ebp), %eax /* 取下一个线程结构体基址*/ 22 | mov %eax, current /* 更新 current */ 23 | mov 8(%eax), %esp /* 切换到下一个线程的栈 */ 24 | 25 | /* 恢复现场, 到这里,已经进入另一个线程环境了,本质是 esp 改变 */ 26 | popfl 27 | popl %eax 28 | popl %edx 29 | popl %ecx 30 | popl %ebx 31 | popl %esi 32 | popl %edi 33 | 34 | popl %ebp 35 | ret 36 | -------------------------------------------------------------------------------- /v3/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | unsigned int getmstime() { 6 | struct timeval tv; 7 | if (gettimeofday(&tv, NULL) < 0) { 8 | perror("gettimeofday"); 9 | exit(-1); 10 | } 11 | return tv.tv_sec * 1000 + tv.tv_usec / 1000; 12 | } 13 | 14 | int main() { 15 | unsigned int start, end; 16 | start = getmstime(); 17 | printf("%u\n", start); 18 | sleep(1); 19 | end = getmstime(); 20 | printf("%u\n", end); 21 | printf("diff = %u\n", end - start); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /v3/thread.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include 3 | 4 | void schedule(); 5 | 6 | static struct task_struct init_task = {0, NULL, 0, {0}}; 7 | 8 | struct task_struct *current = &init_task; 9 | 10 | struct task_struct *task[NR_TASKS] = {&init_task,}; 11 | 12 | // 线程启动函数 13 | static void start(struct task_struct *tsk) { 14 | tsk->th_fn(); 15 | task[tsk->id] = NULL; 16 | schedule(); 17 | } 18 | 19 | int thread_create(int *tid, void (*start_routine)()) { 20 | int id = -1; 21 | struct task_struct *tsk = (struct task_struct*)malloc(sizeof(struct task_struct)); 22 | 23 | while(++id < NR_TASKS && task[id]); 24 | 25 | if (id == NR_TASKS) return -1; 26 | 27 | task[id] = tsk; 28 | 29 | if (tid) *tid = id; 30 | 31 | tsk->id = id; 32 | tsk->th_fn = start_routine; 33 | int *stack = tsk->stack; // 栈顶界限 34 | tsk->esp = (int)(stack+STACK_SIZE-11); 35 | 36 | // 初始 switch_to 函数栈帧 37 | stack[STACK_SIZE-11] = 7; // eflags 38 | stack[STACK_SIZE-10] = 6; // eax 39 | stack[STACK_SIZE-9] = 5; // edx 40 | stack[STACK_SIZE-8] = 4; // ecx 41 | stack[STACK_SIZE-7] = 3; // ebx 42 | stack[STACK_SIZE-6] = 2; // esi 43 | stack[STACK_SIZE-5] = 1; // edi 44 | stack[STACK_SIZE-4] = 0; // old ebp 45 | stack[STACK_SIZE-3] = (int)start; // ret to start 46 | // start 函数栈帧,刚进入 start 函数的样子 47 | stack[STACK_SIZE-2] = 100;// ret to unknown,如果 start 执行结束,表明线程结束 48 | stack[STACK_SIZE-1] = (int)tsk; // start 的参数 49 | 50 | return 0; 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /v3/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __THREAD_H__ 2 | #define __THREAD_H__ 3 | 4 | #define NR_TASKS 16 5 | #define STACK_SIZE 1024 // 1024*4 B 6 | 7 | #define THREAD_RUNNING 0 8 | #define THREAD_SLEEP 1 9 | #define THREAD_EXIT 2 10 | 11 | struct task_struct { 12 | int id; 13 | void (*th_fn)(); 14 | int esp; // 保存 esp 15 | int stack[STACK_SIZE]; 16 | }; 17 | 18 | 19 | int thread_create(int *tid, void (*start_routine)()); 20 | int thread_join(int tid); 21 | void mysleep(int seconds); 22 | 23 | #endif //__THREAD_H__ 24 | -------------------------------------------------------------------------------- /v4/Makefile: -------------------------------------------------------------------------------- 1 | main:main.c thread.c thread.h sched.c switch.s 2 | gcc -g main.c thread.c sched.c switch.s -o main 3 | -------------------------------------------------------------------------------- /v4/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanallen/MyThread/441456848f0e06722392cb798c2ff3c895e1fd71/v4/a.out -------------------------------------------------------------------------------- /v4/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "thread.h" 4 | 5 | 6 | void fun1() { 7 | int i = 10; 8 | while(i--) { 9 | printf("hello, I'm fun1\n"); 10 | mysleep(4); 11 | } 12 | } 13 | 14 | void fun2() { 15 | int i = 10; 16 | while(i--) { 17 | printf("hello, I'm fun2\n"); 18 | mysleep(1); 19 | } 20 | } 21 | 22 | void fun3() { 23 | int i = 2; 24 | while(i--) { 25 | printf("hello, I'm fun3\n"); 26 | mysleep(1); 27 | } 28 | } 29 | 30 | 31 | int main() { 32 | 33 | int tid1, tid2, tid3; 34 | thread_create(&tid1, fun1); 35 | printf("create thread %d\n", tid1); 36 | thread_create(&tid2, fun2); 37 | printf("create thread %d\n", tid2); 38 | thread_create(&tid3, fun3); 39 | printf("create thread %d\n", tid3); 40 | 41 | int i = 2; 42 | while(i--) { 43 | printf("hello, I'm main\n"); 44 | mysleep(3); 45 | } 46 | thread_join(tid1); 47 | thread_join(tid2); 48 | thread_join(tid3); 49 | 50 | return 0; 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /v4/sched.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include 3 | #include 4 | 5 | extern struct task_struct *current; 6 | extern struct task_struct *task[NR_TASKS]; 7 | 8 | void switch_to(struct task_struct *next); 9 | 10 | static unsigned int getmstime() { 11 | struct timeval tv; 12 | if (gettimeofday(&tv, NULL) < 0) { 13 | perror("gettimeofday"); 14 | exit(-1); 15 | } 16 | return tv.tv_sec * 1000 + tv.tv_usec / 1000; 17 | } 18 | 19 | static struct task_struct *pick() { 20 | int current_id = current->id; 21 | int i; 22 | 23 | struct task_struct *next = NULL; 24 | 25 | repeat: 26 | for (i = 0; i < NR_TASKS; ++i) { 27 | if (task[i] && task[i]->status == THREAD_SLEEP) { 28 | if (getmstime() > task[i]->wakeuptime) 29 | task[i]->status = THREAD_RUNNING; 30 | } 31 | } 32 | 33 | i = current_id; 34 | 35 | while(1) { 36 | i = (i + 1) % NR_TASKS; 37 | if (i == current_id) { 38 | // 循环了一圈说明没找到可被调度的线程 39 | goto repeat; 40 | } 41 | if (task[i] && task[i]->status == THREAD_RUNNING) { 42 | next = task[i]; 43 | break; 44 | } 45 | } 46 | 47 | return next; 48 | } 49 | 50 | 51 | 52 | void schedule() { 53 | struct task_struct *next = pick(); 54 | if (next) { 55 | switch_to(next); 56 | } 57 | } 58 | 59 | void mysleep(int seconds) { 60 | current->wakeuptime = getmstime() + 1000*seconds; 61 | current->status = THREAD_SLEEP; 62 | schedule(); 63 | } 64 | -------------------------------------------------------------------------------- /v4/switch.s: -------------------------------------------------------------------------------- 1 | /*void switch_to(struct task_struct *next)*/ 2 | 3 | .section .text 4 | .global switch_to 5 | switch_to: 6 | push %ebp 7 | mov %esp, %ebp /* 更改栈帧,以便寻参 */ 8 | 9 | /* 保存现场 */ 10 | push %edi 11 | push %esi 12 | push %ebx 13 | push %edx 14 | push %ecx 15 | push %eax 16 | pushfl 17 | 18 | /* 准备切换栈 */ 19 | mov current, %eax /* 取 current 基址放到 eax */ 20 | mov %esp, 8(%eax) /* 保存当前 esp 到线程结构体 */ 21 | mov 8(%ebp), %eax /* 取下一个线程结构体基址*/ 22 | mov %eax, current /* 更新 current */ 23 | mov 8(%eax), %esp /* 切换到下一个线程的栈 */ 24 | 25 | /* 恢复现场, 到这里,已经进入另一个线程环境了,本质是 esp 改变 */ 26 | popfl 27 | popl %eax 28 | popl %edx 29 | popl %ecx 30 | popl %ebx 31 | popl %esi 32 | popl %edi 33 | 34 | popl %ebp 35 | ret 36 | -------------------------------------------------------------------------------- /v4/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | unsigned int getmstime() { 6 | struct timeval tv; 7 | if (gettimeofday(&tv, NULL) < 0) { 8 | perror("gettimeofday"); 9 | exit(-1); 10 | } 11 | return tv.tv_sec * 1000 + tv.tv_usec / 1000; 12 | } 13 | 14 | int main() { 15 | unsigned int start, end; 16 | start = getmstime(); 17 | printf("%u\n", start); 18 | sleep(1); 19 | end = getmstime(); 20 | printf("%u\n", end); 21 | printf("diff = %u\n", end - start); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /v4/thread.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include 3 | 4 | void schedule(); 5 | 6 | static struct task_struct init_task = {0, NULL, THREAD_RUNNING, 0, 0, {0}}; 7 | 8 | struct task_struct *current = &init_task; 9 | 10 | struct task_struct *task[NR_TASKS] = {&init_task,}; 11 | 12 | // 线程启动函数 13 | static void start(struct task_struct *tsk) { 14 | tsk->th_fn(); 15 | tsk->status = THREAD_EXIT; 16 | schedule(); 17 | } 18 | 19 | int thread_create(int *tid, void (*start_routine)()) { 20 | int id = -1; 21 | struct task_struct *tsk = (struct task_struct*)malloc(sizeof(struct task_struct)); 22 | 23 | while(++id < NR_TASKS && task[id]); 24 | 25 | if (id == NR_TASKS) return -1; 26 | 27 | task[id] = tsk; 28 | 29 | if (tid) *tid = id; 30 | 31 | tsk->id = id; 32 | tsk->th_fn = start_routine; 33 | int *stack = tsk->stack; // 栈顶界限 34 | tsk->esp = (int)(stack+STACK_SIZE-11); 35 | tsk->wakeuptime = 0; 36 | tsk->status = THREAD_RUNNING; 37 | 38 | // 初始 switch_to 函数栈帧 39 | stack[STACK_SIZE-11] = 7; // eflags 40 | stack[STACK_SIZE-10] = 6; // eax 41 | stack[STACK_SIZE-9] = 5; // edx 42 | stack[STACK_SIZE-8] = 4; // ecx 43 | stack[STACK_SIZE-7] = 3; // ebx 44 | stack[STACK_SIZE-6] = 2; // esi 45 | stack[STACK_SIZE-5] = 1; // edi 46 | stack[STACK_SIZE-4] = 0; // old ebp 47 | stack[STACK_SIZE-3] = (int)start; // ret to start 48 | // start 函数栈帧,刚进入 start 函数的样子 49 | stack[STACK_SIZE-2] = 100;// ret to unknown,如果 start 执行结束,表明线程结束 50 | stack[STACK_SIZE-1] = (int)tsk; // start 的参数 51 | 52 | return 0; 53 | } 54 | 55 | int thread_join(int tid) { 56 | while(task[tid]->status != THREAD_EXIT) { 57 | schedule(); 58 | } 59 | free(task[tid]); 60 | task[tid] = NULL; 61 | } 62 | -------------------------------------------------------------------------------- /v4/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __THREAD_H__ 2 | #define __THREAD_H__ 3 | 4 | #define NR_TASKS 16 5 | #define STACK_SIZE 1024 // 1024*4 B 6 | 7 | #define THREAD_RUNNING 0 8 | #define THREAD_SLEEP 1 9 | #define THREAD_EXIT 2 10 | 11 | struct task_struct { 12 | int id; 13 | void (*th_fn)(); 14 | int esp; // 保存 esp 15 | unsigned int wakeuptime; // 线程唤醒时间 16 | int status; 17 | int stack[STACK_SIZE]; 18 | }; 19 | 20 | 21 | int thread_create(int *tid, void (*start_routine)()); 22 | int thread_join(int tid); 23 | void mysleep(int seconds); 24 | 25 | #endif //__THREAD_H__ 26 | -------------------------------------------------------------------------------- /v5/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | main 4 | -------------------------------------------------------------------------------- /v5/Makefile: -------------------------------------------------------------------------------- 1 | main: main.c thread.c sched.c switch.s thread.h 2 | gcc -g main.c thread.c sched.c switch.s -o main 3 | -------------------------------------------------------------------------------- /v5/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "thread.h" 4 | 5 | 6 | void fun1() { 7 | int i = 10; 8 | while(i--) { 9 | printf("hello, I'm fun1\n"); 10 | mysleep(2); 11 | } 12 | } 13 | 14 | void fun2() { 15 | int i = 10; 16 | while(i--) { 17 | printf("hello, I'm fun2\n"); 18 | mysleep(1); 19 | } 20 | } 21 | 22 | void fun3() { 23 | int i = 2; 24 | while(i--) { 25 | printf("hello, I'm fun3\n"); 26 | mysleep(5); 27 | } 28 | } 29 | 30 | void fun4() { 31 | int i = 15; 32 | int m; 33 | int n; 34 | while(i--) { 35 | printf("hello, I'm fun4\n"); 36 | // sleep 会失效(因为有信号产生),这里用循环。 37 | for (m = 0; m < 10000; ++m) 38 | for (n = 0; n < 10000; ++n); 39 | } 40 | } 41 | 42 | int main() { 43 | 44 | int tid1, tid2, tid3, tid4; 45 | thread_create(&tid1, fun1); 46 | printf("create thread %d\n", tid1); 47 | thread_create(&tid2, fun2); 48 | printf("create thread %d\n", tid2); 49 | thread_create(&tid3, fun3); 50 | printf("create thread %d\n", tid3); 51 | thread_create(&tid4, fun4); 52 | printf("create thread %d\n", tid4); 53 | 54 | int i = 2; 55 | while(i--) { 56 | printf("hello, I'm main\n"); 57 | mysleep(3); 58 | } 59 | thread_join(tid1); 60 | thread_join(tid2); 61 | thread_join(tid3); 62 | thread_join(tid4); 63 | 64 | return 0; 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /v5/sched.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern struct task_struct *current; 8 | extern struct task_struct *task[NR_TASKS]; 9 | 10 | void switch_to(struct task_struct *next); 11 | 12 | static unsigned int getmstime() { 13 | struct timeval tv; 14 | if (gettimeofday(&tv, NULL) < 0) { 15 | perror("gettimeofday"); 16 | exit(-1); 17 | } 18 | return tv.tv_sec * 1000 + tv.tv_usec / 1000; 19 | } 20 | 21 | static struct task_struct *pick() { 22 | int i, next, c; 23 | 24 | 25 | for (i = 0; i < NR_TASKS; ++i) { 26 | if (task[i] && task[i]->status != THREAD_EXIT 27 | && getmstime() > task[i]->wakeuptime) { 28 | task[i]->status = THREAD_RUNNING; 29 | } 30 | } 31 | 32 | while(1) { 33 | c = -1; 34 | next = 0; 35 | for (i = 0; i < NR_TASKS; ++i) { 36 | if (!task[i]) continue; 37 | if (task[i]->status == THREAD_RUNNING && task[i]->counter > c) { 38 | c = task[i]->counter; 39 | next = i; 40 | } 41 | } 42 | if (c) break; 43 | 44 | // 如果所有任务时间片都是 0,重新调整时间片的值 45 | if (c == 0) { 46 | for (i = 0; i < NR_TASKS; ++i) { 47 | if(task[i]) { 48 | task[i]->counter = task[i]->priority + (task[i]->counter >> 1); 49 | } 50 | } 51 | } 52 | } 53 | 54 | return task[next]; 55 | } 56 | 57 | void closealarm() { 58 | sigset_t mask; 59 | sigemptyset(&mask); 60 | sigaddset(&mask, SIGALRM); 61 | if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { 62 | perror("sigprocmask BLOCK"); 63 | } 64 | } 65 | 66 | void openalarm() { 67 | sigset_t mask; 68 | sigemptyset(&mask); 69 | sigaddset(&mask, SIGALRM); 70 | if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { 71 | perror("sigprocmask BLOCK"); 72 | } 73 | } 74 | 75 | 76 | void schedule() { 77 | struct task_struct *next = pick(); 78 | if (next) { 79 | switch_to(next); 80 | } 81 | // schedule 永远不会返回 82 | } 83 | 84 | void mysleep(int seconds) { 85 | current->wakeuptime = getmstime() + 1000*seconds; 86 | current->status = THREAD_SLEEP; 87 | schedule(); 88 | } 89 | 90 | static void do_timer() { 91 | if (--current->counter > 0) return; 92 | current->counter = 0; 93 | schedule(); 94 | //printf("do_timer\n"); 95 | } 96 | 97 | __attribute__((constructor)) 98 | static void init() { 99 | struct itimerval value; 100 | value.it_value.tv_sec = 0; 101 | value.it_value.tv_usec = 1000; 102 | value.it_interval.tv_sec = 0; 103 | value.it_interval.tv_usec = 1000*10; // 10 ms 104 | if (setitimer(ITIMER_REAL, &value, NULL) < 0) { 105 | perror("setitimer"); 106 | } 107 | signal(SIGALRM, do_timer); 108 | } 109 | -------------------------------------------------------------------------------- /v5/switch.s: -------------------------------------------------------------------------------- 1 | /*void switch_to(struct task_struct *next)*/ 2 | 3 | .section .text 4 | .global switch_to 5 | switch_to: 6 | call closealarm /* 模拟关中断 */ 7 | push %ebp 8 | mov %esp, %ebp /* 更改栈帧,以便寻参 */ 9 | 10 | /* 保存现场 */ 11 | push %edi 12 | push %esi 13 | push %ebx 14 | push %edx 15 | push %ecx 16 | push %eax 17 | pushfl 18 | 19 | /* 准备切换栈 */ 20 | mov current, %eax /* 取 current 基址放到 eax */ 21 | mov %esp, 8(%eax) /* 保存当前 esp 到线程结构体 */ 22 | mov 8(%ebp), %eax /* 取下一个线程结构体基址*/ 23 | mov %eax, current /* 更新 current */ 24 | mov 8(%eax), %esp /* 切换到下一个线程的栈 */ 25 | 26 | /* 恢复现场, 到这里,已经进入另一个线程环境了,本质是 esp 改变 */ 27 | popfl 28 | popl %eax 29 | popl %edx 30 | popl %ecx 31 | popl %ebx 32 | popl %esi 33 | popl %edi 34 | 35 | popl %ebp 36 | call openalarm /* 模拟开中断 */ 37 | ret 38 | -------------------------------------------------------------------------------- /v5/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void handler(int sig) { 7 | if (sig == SIGALRM) { 8 | printf("SIGALRM\n"); 9 | } 10 | } 11 | __attribute__((constructor)) 12 | void init() { 13 | printf("construct\n"); 14 | if (signal(SIGALRM, handler) == SIG_ERR) { 15 | perror("signal"); 16 | } 17 | } 18 | 19 | 20 | __attribute__((destructor)) 21 | void destory() { 22 | printf("destruct\n"); 23 | } 24 | 25 | 26 | int main() { 27 | struct itimerval value; 28 | value.it_value.tv_sec = 0; 29 | value.it_value.tv_usec = 1000*20; 30 | value.it_interval.tv_sec = 0; 31 | value.it_interval.tv_usec = 1000*20; 32 | if (setitimer(ITIMER_REAL, &value, NULL) < 0) { 33 | perror("setitimer"); 34 | } 35 | while(1) sleep(1); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /v5/thread.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | void schedule(); 10 | 11 | static struct task_struct init_task = {0, NULL, THREAD_RUNNING, 0, 0, 15, 15, {0}}; 12 | 13 | struct task_struct *current = &init_task; 14 | 15 | struct task_struct *task[NR_TASKS] = {&init_task,}; 16 | 17 | // 线程启动函数 18 | static void start(struct task_struct *tsk) { 19 | tsk->th_fn(); 20 | tsk->status = THREAD_EXIT; 21 | printf("thread [%d] exited\n", tsk->id); 22 | schedule(); 23 | // 下面这一行永远不会被执行 24 | printf("thread [%d] resume\n", tsk->id); 25 | } 26 | 27 | int thread_create(int *tid, void (*start_routine)()) { 28 | int id = -1; 29 | struct task_struct *tsk = (struct task_struct*)malloc(sizeof(struct task_struct)); 30 | 31 | while(++id < NR_TASKS && task[id]); 32 | 33 | if (id == NR_TASKS) return -1; 34 | 35 | task[id] = tsk; 36 | 37 | if (tid) *tid = id; 38 | 39 | tsk->id = id; 40 | tsk->th_fn = start_routine; 41 | int *stack = tsk->stack; // 栈顶界限 42 | tsk->esp = (int)(stack+STACK_SIZE-11); 43 | tsk->wakeuptime = 0; 44 | tsk->status = THREAD_RUNNING; 45 | tsk->counter = 15; 46 | tsk->priority = 15; 47 | 48 | // 初始 switch_to 函数栈帧 49 | stack[STACK_SIZE-11] = 7; // eflags 50 | stack[STACK_SIZE-10] = 6; // eax 51 | stack[STACK_SIZE-9] = 5; // edx 52 | stack[STACK_SIZE-8] = 4; // ecx 53 | stack[STACK_SIZE-7] = 3; // ebx 54 | stack[STACK_SIZE-6] = 2; // esi 55 | stack[STACK_SIZE-5] = 1; // edi 56 | stack[STACK_SIZE-4] = 0; // old ebp 57 | stack[STACK_SIZE-3] = (int)start; // ret to start 58 | // start 函数栈帧,刚进入 start 函数的样子 59 | stack[STACK_SIZE-2] = 100;// ret to unknown,如果 start 执行结束,表明线程结束 60 | stack[STACK_SIZE-1] = (int)tsk; // start 的参数 61 | 62 | return 0; 63 | } 64 | 65 | int thread_join(int tid) { 66 | while(task[tid]->status != THREAD_EXIT) { 67 | schedule(); 68 | } 69 | free(task[tid]); 70 | task[tid] = NULL; 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /v5/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __THREAD_H__ 2 | #define __THREAD_H__ 3 | 4 | #define NR_TASKS 16 5 | #define STACK_SIZE 1024 // 1024*4 B 6 | 7 | #define THREAD_READY 0 8 | #define THREAD_RUNNING 1 9 | #define THREAD_SLEEP 2 10 | #define THREAD_EXIT 3 11 | 12 | struct task_struct { 13 | /******** 这三行不能动 ***********/ 14 | int id; 15 | void (*th_fn)(); 16 | int esp; // 保存 esp 17 | /*********************************/ 18 | 19 | unsigned int wakeuptime; // 线程唤醒时间 20 | int status; // 线程状态 21 | int counter; // 时间片 22 | int priority; // 线程优先级 23 | int stack[STACK_SIZE]; 24 | }; 25 | 26 | 27 | int thread_create(int *tid, void (*start_routine)()); 28 | int thread_join(int tid); 29 | void mysleep(int seconds); 30 | 31 | #endif //__THREAD_H__ 32 | --------------------------------------------------------------------------------