“郭孟琦 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”
貌似是最后一周课了,竟然坚持下来了!!!!
1、在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确;
一搜吓了一大跳,
Searched full:schedule (Results 1 - 25 of 1213) sorted by relevance
看来直接挨个看是不太实际了,这里我重点挑出了之前的课程内容中出现的schedule
想了想发现这实际上就是探究linux进程调度的时机
Linux进程调度时机主要有:
1、进程状态转换的时刻:进程终止、进程睡眠;
2、当前进程的时间片用完时(current->counter=0);
3、设备驱动程序
4、进程从中断、异常及系统调用返回到用户态时;
时机1,进程要调用sleep()或exit()等函数进行状态转换,这些函数会主动调用调度程序进行进程调度;
时机2,由于进程的时间片是由时钟中断来更新的,因此,这种情况和时机4是一样的。
时机3,当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,驱动程序都检查need_resched的值,如果必要,则调用调度程序schedule()主动放弃CPU。
时机4,在system_call的结尾调用
596work_resched:
597 call schedule
598 LOCKDEP_SYS_EXIT
2、使用gdb跟踪分析一个schedule()函数
在系统调用结束后
确实调用了schedule,在跟踪时无法直接追踪汇编函数switch_to,因此还是直接分析代码吧
#define switch_to(prev, next, last) \
32do { \
33 /* \
34 * Context-switching clobbers all registers, so we clobber \
35 * them explicitly, via unused output variables. \
36 * (EAX and EBP is not listed because EBP is saved/restored \
37 * explicitly for wchan access and EAX is the return value of \
38 * __switch_to()) \
39 */ \
40 unsigned long ebx, ecx, edx, esi, edi; \
41 \
42 asm volatile("pushfl\n\t" /* save flags */ \
43 "pushl %%ebp\n\t" /* save EBP */ \
44 "movl %%esp,%[prev_sp]\n\t" /* save ESP */ \
45 "movl %[next_sp],%%esp\n\t" /* restore ESP */ \
46 "movl $1f,%[prev_ip]\n\t" /* save EIP */ \
47 "pushl %[next_ip]\n\t" /* restore EIP */ \
48 __switch_canary \
49 "jmp __switch_to\n" /* regparm call */ \
50 "1:\t" \
51 "popl %%ebp\n\t" /* restore EBP */ \
52 "popfl\n" /* restore flags */ \
53 \
54 /* output parameters */ \
55 : [prev_sp] "=m" (prev->thread.sp), \
56 [prev_ip] "=m" (prev->thread.ip), \
57 "=a" (last), \
58 \
59 /* clobbered output registers: */ \
60 "=b" (ebx), "=c" (ecx), "=d" (edx), \
61 "=S" (esi), "=D" (edi) \
62 \
63 __switch_canary_oparam \
64 \
65 /* input parameters: */ \
66 : [next_sp] "m" (next->thread.sp), \
67 [next_ip] "m" (next->thread.ip), \
68 \
69 /* regparm parameters for __switch_to(): */ \
70 [prev] "a" (prev), \
71 [next] "d" (next) \
72 \
73 __switch_canary_iparam \
74 \
75 : /* reloaded segment registers */ \
76 "memory"); \
77} while (0)
这一过程非常 像一个超简单的系统内核 中的切换过程
1、新进程执行过,对于执行过的进程,只要保存好现在的现场(ebp存入堆栈中,esp(指向刚刚存进去的ebp)放入之前的thread结构体的sp中,eip放入thread结构体的ip中),恢复刚才的现场,也就是将新进程的eip,esp,ebp放出来。esp是直接从sp中赋给esp,eip从ip放入栈再通过ret弹出来(因为eip不能被直接修改),此时esp是指向刚才的ebp的(想不明白可以看esp存到sp里时指的是谁?)。但是弹出ebp这个过程要在ret之后,因为那个eip存的时候是指的1:,新的进程自然就会在它的1:处恢复
总结:学习完这门课 对堆栈 进程 有了很深刻的认识,也解决了ucos学习中不理解的很多问题。