当进程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从内核态返回当用户态,继续执行下一条指令。

附:

_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 }

转载于:https://www.cnblogs.com/roma823/archive/2011/05/12/2101259.html

switch_to及ret_from_sys_call控制任务的切换与返回相关推荐

  1. Vue2.0使用嵌套路由实现页面内容切换/公用一级菜单控制页面内容切换

    vue2.0使用嵌套路由实现页面跳转切换/公用一级菜单控制页面内容切换/routes配置children demo需求分析: 图中菜单区域为header公用组件,点击相应的菜单选项跳转到对应的路由,在 ...

  2. html鼠标滑轮换图片,JavaScript实现鼠标滚轮控制页面图片切换

    鼠标上的滚轮是一个不错的东东,为什么这么说,因为它能帮助我们快速的浏览网页,快速的进行长篇文章的阅读.对于web前端的我们来说又怎么能不注重这个鼠标滚轮呢,那么它能如何让用户更好的浏览网页呢?本文主要 ...

  3. python居然能语音控制电脑壁纸切换,只需60行代码

    前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 家在日常的电脑使用中,都会有自己喜爱类型的桌面 单纯的桌面有时候会让人觉得单调 今天,就由我带领大家只用60行代码打造一款语音壁纸切换器程序, 让大家能够 ...

  4. 基于simulink的VSG并网逆变器仿真——VSG控制——离并网切换——虚拟同步发电机技术

    基于simulink的VSG并网逆变器仿真--VSG控制--离并网切换--虚拟同步发电机技术 采用VSG控制,并网前带动5000W负载. 输出电压幅值和频率稳定后,启动并网预同步控制,满足并网条件后, ...

  5. 【3D商城】鼠标滚动控制全屏切换

    [3D商城]鼠标滚动控制全屏切换 ajax请求获取服务器数据 设置加载loading组件 产品列表和场景列表的编写 监听鼠标滚动事件 列表标签中显示设置隐藏属性 头部标签中显示设置隐藏属性 结果 aj ...

  6. 60行代码出炫酷效果之 python语音控制电脑壁纸切换

    前言 大家早好.午好.晚好吖 ❤ ~欢迎光临本文章 电脑大家有吧!手大家有吧!今天!! 就由我带领大家用区区60行代码打造一款语音壁纸切换器程序!!! 单纯的桌面有时候会让人觉得单调,那么~ 让大家能 ...

  7. SpringMVC控制类的Controller方法返回值

    SpringMVC控制类的Controller方法返回值 Controller方法返回值 返回字符串 逻辑视图名 controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址 ...

  8. Android 距离感应器和耳机状态监测(控制Audio输出通道切换)

    * 切换扬声器播放声音 or 听筒播放  * 1. 距离感应器:继承SensorEventListener这个监听,重写onSensorChanged方法  * 2. 检测耳机插入和拔出:Headse ...

  9. C# 多线程控制 通讯 和切换

    一.多线程的概念  Windows是一个多任务的系统,如果你使用的是windows 2000及其以上版本,你可以通过任务管理器查看当前系统运行的程序和进程.什么是进程呢?当一个程序开始运行时,它就是一 ...

最新文章

  1. 基于Cobbler实现多版本系统批量部署
  2. Ubuntu 进入、退出命令行的快捷键
  3. 故障转移集群无法连接到节点_Redis集群以及自动故障转移测试
  4. java 查看pdf_Java中实现pdf在线查看和下载
  5. concurrent: Callable用法
  6. ELK之elasticsearch5.6的安装和head插件的安装
  7. 基于Java实现的快速排序
  8. 《Python CookBook2》 第一章 文本 - 测试一个对象是否是类字符串 字符串对齐
  9. C++实现NV12格式转BGR
  10. 10个宝藏级编程资源
  11. 参数曲面matlab,MATLAB空间曲面的实现方法
  12. netty官方例子 三 http snoop监听
  13. UVA 10066 10192
  14. Solidworks如何打开swb文件
  15. 机器视觉OpenCV-sobel、robert、gauss算子边缘检测
  16. 20159318 《网络攻防实践》第2周学习总结
  17. 云上架构和传统IT架构的区别在哪里?(企业CIO、CTO必读)
  18. 为什么hashmap的容量必须是2的n次幂
  19. LeeCode:救生艇(贪心)
  20. 【Linux入门指北】Linux实验综合训练

热门文章

  1. ubuntu下docker的安装及更换镜像源
  2. 异常解决(二)-- AttributeError: cannot assign module before Module.__init__() call
  3. vysor原理代码实现(V2.0)
  4. 安卓代码跟踪方式学习笔记
  5. android广告轮播图之匀速规律播放
  6. axios发送登录请求_使用axios实现登录功能(前后端联调)
  7. JZOJ 3806. 【NOIP2014模拟8.24】小X 的道路修建
  8. JavaScript怎么安装_几句话说清楚JavaScript、V8引擎、NodeJS、NMP,到底是什么东东...
  9. 服务器部署的参数文档,服务器的基本配置参数
  10. 判断直线与线段是否相交,相交则输出交点x轴坐标