当进程A在用户态下执行着,出现了系统调用(int 0x80),CPU转而执行_system_call(system_call.s L80)中断处理过程,

     _system_call 保持了进程A在用户态时的现场信息,然后执行call _sys_call_table(, %eax, 4)指令,当执行完本指令时,进程

     A请求的系统调用已经完成了,_system_call剩下的代码是该系统调用中断处理过程的退出阶段。

     当执行到jne reschedule时,处于内核态的进程A希望主动放弃CPU,实现进程调度,reschedule代码如下:

     reschedule:

                 pushl   $ret_from_sys_call

                 jmp  _schedule

     先将ret_from_sys_call地址入栈,然后跳转到sched.c L104 函数schedule入口处执行该函数,当执行到switch_to(next)时,

     如果此时next = B,意味着CPU的使用权将从进程A切换到进程B,当在switch_to(next)中执行完指令ljmp %0/n/t时,此时

     CPU自动将进程A的内核态现场环境保存到A对应的tss中,例如将ss, esp保存为进程A内核态堆栈,

     将cs保存为0x0008(内核代码段)将eip保存为switch_to(next)中指令cmpl %%ecx,_last_task_used_math/n/t的地址

    (即当下一次CPU重新切换到进程A时, 即将执行的指令)。

     当CPU将进程A内核态的现在保存完毕时,又自动将进程B对应的tss中的现在信息加载到CPU的寄存器中,

     这样CPU就开始执行进程B的指令了。

     一段时间后,CPU控制权再次切换到进程A中(此时进程A处于内核态,进程A之前占有CPU的进程X执行了switch_to(B)),

     此时cs = 0x0008,eip等于指令cmpl %%ecx,_last_task_used_math/n/t的地址,故而进程A执行指令cmpl %%

     ecx,_last_task_used_math,接着执行jne 1f/n/t,clts/n,当执行完clts/n指令后,接着执行ret指令,此时eip等于

     ret_from_sys_call的地址,故而函数schedule执行完毕,程序返回到ret_from_sys_call处继续执行。

     执行movl _current, %eax,_current指向进程A的struct tast_struct(进程A的任务数据结构),如果是进程A是任务0,则

     立即跳出进程A的系统调用中断处理程序;执行cmpw $0x0f,CS(%esp),如果进程A用户态的cs不是普通用户代码段,则退出;

     执行cmpw $0x17,OLDSS(%esp),如果进程A用户态堆栈不在用户数据段中,则退出。

     当排除了以上可能后,确定了进程A是一个普通的用户态进程(区别于cs=0x08,ds=ss=0x10的进程--内核进程

     (这个称呼可能不准确)),然后进行信号量处理,处理完信号量后,执行L121处标号3的代码,进程A的系统调用中断处理程序

     全部结束,进程A从内核态返回当用户态,继续执行下一条指令。

     附:  

swich 返回值 java_内核态

swich 返回值 java_内核态_02

_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

  

swich 返回值 java_内核态

swich 返回值 java_内核态_02

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 }

     

swich 返回值 java_内核态

swich 返回值 java_内核态_02

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 }