switch_to及ret_from_sys_call控制任务的切换与返回
???? 當(dāng)進(jìn)程A在用戶態(tài)下執(zhí)行著,出現(xiàn)了系統(tǒng)調(diào)用(int 0x80),CPU轉(zhuǎn)而執(zhí)行_system_call(system_call.s L80)中斷處理過(guò)程,
???? _system_call 保持了進(jìn)程A在用戶態(tài)時(shí)的現(xiàn)場(chǎng)信息,然后執(zhí)行call _sys_call_table(, %eax, 4)指令,當(dāng)執(zhí)行完本指令時(shí),進(jìn)程
???? A請(qǐng)求的系統(tǒng)調(diào)用已經(jīng)完成了,_system_call剩下的代碼是該系統(tǒng)調(diào)用中斷處理過(guò)程的退出階段。
???? 當(dāng)執(zhí)行到j(luò)ne reschedule時(shí),處于內(nèi)核態(tài)的進(jìn)程A希望主動(dòng)放棄CPU,實(shí)現(xiàn)進(jìn)程調(diào)度,reschedule代碼如下:
???? reschedule:
???????????????? pushl?? $ret_from_sys_call
???????????????? jmp? _schedule
???? 先將ret_from_sys_call地址入棧,然后跳轉(zhuǎn)到sched.c L104 函數(shù)schedule入口處執(zhí)行該函數(shù),當(dāng)執(zhí)行到switch_to(next)時(shí),
???? 如果此時(shí)next = B,意味著CPU的使用權(quán)將從進(jìn)程A切換到進(jìn)程B,當(dāng)在switch_to(next)中執(zhí)行完指令ljmp %0/n/t時(shí),此時(shí)
???? CPU自動(dòng)將進(jìn)程A的內(nèi)核態(tài)現(xiàn)場(chǎng)環(huán)境保存到A對(duì)應(yīng)的tss中,例如將ss, esp保存為進(jìn)程A內(nèi)核態(tài)堆棧,
???? 將cs保存為0x0008(內(nèi)核代碼段)將eip保存為switch_to(next)中指令cmpl %%ecx,_last_task_used_math/n/t的地址
??? (即當(dāng)下一次CPU重新切換到進(jìn)程A時(shí),?即將執(zhí)行的指令)。
???? 當(dāng)CPU將進(jìn)程A內(nèi)核態(tài)的現(xiàn)在保存完畢時(shí),又自動(dòng)將進(jìn)程B對(duì)應(yīng)的tss中的現(xiàn)在信息加載到CPU的寄存器中,
???? 這樣CPU就開(kāi)始執(zhí)行進(jìn)程B的指令了。
???? 一段時(shí)間后,CPU控制權(quán)再次切換到進(jìn)程A中(此時(shí)進(jìn)程A處于內(nèi)核態(tài),進(jìn)程A之前占有CPU的進(jìn)程X執(zhí)行了switch_to(B)),
???? 此時(shí)cs = 0x0008,eip等于指令cmpl %%ecx,_last_task_used_math/n/t的地址,故而進(jìn)程A執(zhí)行指令cmpl %%
???? ecx,_last_task_used_math,接著執(zhí)行jne 1f/n/t,clts/n,當(dāng)執(zhí)行完clts/n指令后,接著執(zhí)行ret指令,此時(shí)eip等于
???? ret_from_sys_call的地址,故而函數(shù)schedule執(zhí)行完畢,程序返回到ret_from_sys_call處繼續(xù)執(zhí)行。
???? 執(zhí)行movl _current, %eax,_current指向進(jìn)程A的struct tast_struct(進(jìn)程A的任務(wù)數(shù)據(jù)結(jié)構(gòu)),如果是進(jìn)程A是任務(wù)0,則
???? 立即跳出進(jìn)程A的系統(tǒng)調(diào)用中斷處理程序;執(zhí)行cmpw $0x0f,CS(%esp),如果進(jìn)程A用戶態(tài)的cs不是普通用戶代碼段,則退出;
???? 執(zhí)行cmpw $0x17,OLDSS(%esp),如果進(jìn)程A用戶態(tài)堆棧不在用戶數(shù)據(jù)段中,則退出。
???? 當(dāng)排除了以上可能后,確定了進(jìn)程A是一個(gè)普通的用戶態(tài)進(jìn)程(區(qū)別于cs=0x08,ds=ss=0x10的進(jìn)程--內(nèi)核進(jìn)程
???? (這個(gè)稱呼可能不準(zhǔn)確)),然后進(jìn)行信號(hào)量處理,處理完信號(hào)量后,執(zhí)行L121處標(biāo)號(hào)3的代碼,進(jìn)程A的系統(tǒng)調(diào)用中斷處理程序
???? 全部結(jié)束,進(jìn)程A從內(nèi)核態(tài)返回當(dāng)用戶態(tài),繼續(xù)執(zhí)行下一條指令。
???? 附:??
_system_call 1 _system_call:2 cmpl $nr_system_calls-1,%eax
3 ja bad_sys_call
4 push %ds
5 push %es
6 push %fs
7 pushl %edx
8 pushl %ecx # push %ebx,%ecx,%edx as parameters
9 pushl %ebx # to the system call
10 movl $0x10,%edx # set up ds,es to kernel space
11 mov %dx,%ds
12 mov %dx,%es
13 movl $0x17,%edx # fs points to local data space
14 mov %dx,%fs
15 call _sys_call_table(,%eax,4)
16 pushl %eax
17 movl _current,%eax
18 cmpl $0,state(%eax) # state
19 jne reschedule
20 cmpl $0,counter(%eax) # counter
21 je reschedule
22 ?ret_from_sys_call:
23 movl _current,%eax # task[0] cannot have signals
24 cmpl _task,%eax
25 je 3f
26 cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
27 jne 3f
28 cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
29 jne 3f
30 movl signal(%eax),%ebx
31 movl blocked(%eax),%ecx
32 notl %ecx
33 andl %ebx,%ecx
34 bsfl %ecx,%ecx
35 je 3f
36 btrl %ecx,%ebx
37 movl %ebx,signal(%eax)
38 incl %ecx
39 pushl %ecx
40 call _do_signal
41 popl %eax
42 ?3: popl %eax
43 popl %ebx
44 popl %ecx
45 popl %edx
46 pop %fs
47 pop %es
48 pop %ds
49 iret
?
schedule 1 void schedule(void)2 {
3 int i,next,c;
4 struct task_struct ** p;
5
6 /* check alarm, wake up any interruptible tasks that have got a signal */
7
8 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
9 if (*p) {
10 if ((*p)->alarm && (*p)->alarm < jiffies) {
11 (*p)->signal |= (1<<(SIGALRM-1));
12 (*p)->alarm = 0;
13 }
14 if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
15 (*p)->state==TASK_INTERRUPTIBLE)
16 (*p)->state=TASK_RUNNING;
17 }
18
19 /* this is the scheduler proper: */
20
21 while (1) {
22 c = -1;
23 next = 0;
24 i = NR_TASKS;
25 p = &task[NR_TASKS];
26 while (--i) {
27 if (!*--p)
28 continue;
29 if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
30 c = (*p)->counter, next = i;
31 }
32 if (c) break;
33 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
34 if (*p)
35 (*p)->counter = ((*p)->counter >> 1) +
36 (*p)->priority;
37 }
38 switch_to(next);
39 }
?????
switch_to 1 #define switch_to(n) {\2 struct {long a,b;} __tmp; \
3 __asm__("cmpl %%ecx,_current\n\t" \
4 "je 1f\n\t" \
5 "movw %%dx,%1\n\t" \
6 "xchgl %%ecx,_current\n\t" \
7 "ljmp %0\n\t" \
8 "cmpl %%ecx,_last_task_used_math\n\t" \
9 "jne 1f\n\t" \
10 "clts\n" \
11 "1:" \
12 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
13 "d" (_TSS(n)),"c" ((long) task[n])); \
14 }
轉(zhuǎn)載于:https://www.cnblogs.com/roma823/archive/2011/05/12/2101259.html
總結(jié)
以上是生活随笔為你收集整理的switch_to及ret_from_sys_call控制任务的切换与返回的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Silverlight实用窍门系列:40
- 下一篇: iOS用户设计指南-特别说明