ImageVerifierCode 换一换
格式:DOCX , 页数:23 ,大小:30.84KB ,
资源ID:2147744      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/2147744.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(LINUX进程调度机制及其堆栈切换分析.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

LINUX进程调度机制及其堆栈切换分析.docx

1、LINUX进程调度机制及其堆栈切换分析LINUX2.4.18进程调度机制及其堆栈切换分析张华强2004081 LINUX调度机制概述LINUX的进程调度机制的设计主要是从下面三个方面来考虑的。调度的时机,LINUX的进程调度分为主动调度和被动的调度。其中主动的调度在内核空间通过调用schedule()函数来启动一次调度。在用户空间则是通过调用延时、睡眠、退出等主动放弃运行权的系统调用接口进入内核空间并最终通过调用schedule()函数来是启动一次调度。而被动的调度则发生每次处理中断或异常后从系统空间切换到用户空间的前夕,或者经过其他的系统调用返回到用户空间的前夕。调度的策略,为了适应各种不同

2、的应用,LINUX在从UNIX上继承下来的基于优先级的调度策略的基础上实现了三种调度策略:SCHED_FIFO、SCHED_RR和SCHED_OTHER。其中的SCHE_FIFO和SCHED_RR都是实时调度的策略,他们在系统中被赋予了至少1000的优先权值。二者不同的地方在于对待同等优先权值的进程的处理方式上的差别。当系统中有多个同等优先级的SCHED_FIFO进程就绪时,按照先入先出的原则只有当前进程运行到自动放弃CPU的权限时才会让同等优先级的另一个进程调度起来运行。而对于SCHED_RR的进程,则会在每次时钟中断到来时检查先前进程的时间片是否用完,如果用完则剥夺当前进程的CPU使用权调

3、度出同等优先级的另一个SCHED_RR进程运行。SCHED_OTHER则为传统的调度策略,主要用于交互式应用。调度的方式:LINUX内核的调度采用有条件的可剥夺方式,当进程在用户空间运行时,一旦有必要,例如发生了外部中断或者进程的时间片到时,内核都可以剥夺当前进程的运行权而调度其他的进程运行,因而说这种调度方式是可剥夺的,但当进入内核态时,即使内核知道应该调度了,但这种调度并不会立即发生,只有当前进程回到用户空间的前夕这种调度才会发生。根据上面的分析可以得出以下几点结论:1、LINUX的进程调度与中断是密不可分的(即使是系统调用也是通过软件中断INT 0x80来实现的)。2、由于不论是主动的调

4、度还是被动的调度最终都是通过在内核空间中调用schedule函数来实现的,因此LINUX的进程切换一定是在系统空间中完成的,在下面的分析中还可以看到这个过程实际上就是在schedule函数中完成的。2 LINUX2.4.18调度时的堆栈切换分析基于以上两点我们假设系统中目前有两个进程,进程1和进程2,进程1正在运行。下面我们就分别分析在被动调度(中断发生了)和主动调度(调用nanosleep)时系统的堆栈切换情况和进程的调度实现。2.1 被动调度时的堆栈切换分析首先我们分析被动调度的情况。假设进程1正在用户空间运行的过程中来了一个外设的中断请求。根据CPU对中断的响应规则,CPU会在进程的当前

5、指令执行完毕后相应中断。CPU响应中断的过程如下描述。由于在LINUX中只使用了CPU的0和3这两个运行级别,因此在以下的讨论中涉及到CPU的运行级别时只考虑这两个运行级。首先CPU从中断控制器中取得中断向量,然后根据该向量重IDT中取出一个初始化好的中断门并试图穿过该中断门进入相应得中断服务程序中。在穿过中断门的过程中,根据INTEL IA-32体系结构中设计的硬件机制,CPU将作如下工作:首先CPU将其当前运行级别与中断门中要求的运行级别进行比较,如果发现CPU的当前运行级别低于中断门的描述符运行级别(即CPL=3,中断门的DPL=0)时,CPU首先会将由TR寄存器选择的TSS段中的SS0

6、和ESP0(运行级别0的堆栈)装入CPU的SS和ESP中,从后面的分析可知,SS0和ESP0一定对应的是当前运行任务的系统堆栈指针。通过这样就完成了用户空间堆栈到系统空间堆栈的切换。堆栈切换完成之后,CPU紧接着就将当前进程的用户空间堆栈的SS和ESP值压入新的堆栈中,然后在将当前的EFLAGS值和CS、EIP值,这些就对应当前任务被中断时的CPU标志寄存器值和中断处理完成后返回当前进程的地址。如果发现CPU的当前运行级和描述符的运行级一致则不进行堆栈切换而直接将EFLAGS、CS、EIP的值压入堆栈中。不管上述哪种情况,穿过中断门后的堆栈都会是当前任务的系统空间堆栈。由于中断发生在用户空间,

7、因此中断发生时的CPL=3,因而必然会发生堆栈切换。因此进入中断服务入口处时系统堆栈情况如图1所示。返回进程1被中断处的指令地址用户空间堆栈指针用户空间SS用户空间ESPEFLAGS用户空间CS用户空间EIP系统空间堆栈当前ESP图1 进入中断服务程序入口处的系统堆栈从后面的分析可知由于CPU每次使用内核堆栈时对其所作的操作都是均衡的,因此每次从用户空间堆栈切换到系统空间堆栈时,该堆栈都是空的。穿过中断门后系统进入中断服务程序的入口。在LINUX系统中所有中断服务程序的总入口都是由gcc预生成的,具有如下形式:asmlinkage void IRQ0xYY_interrupt(); _asm_

8、( n“IRQ_0xYY_interrupt:ntpushl $#nr-256nt jmp common_interrupt);上述代码中的YY代表外部中断0254的16进制值(其中系统调用0x80除外,它是由系统另外单独初始化的)。根据上述代码可以看出所有的外部中断都是统一进入common_interrup的地方进行处理的。同样该段由gcc预处理出来的代码如下:asmlinkage void call_do_IRQ(void); _asm_( n _ALIGN_STRn common_interrupt:nt SAVE_ALL call_do_IRQ:nt call do_IRQ nt jm

9、p ret_from_intrn);上述代码的主要作用就是通过SAVE_ALL宏将CPU的当前寄存器内容入栈。SAVE_ALL宏的定义如下:#define SAVE_ALL cldnt pushl %esnt pushl %dsnt pushl %eaxnt pushl %ebpnt pushl %edint pushl %esint pushl %edxnt pushl %ecxnt pushl %ebxnt movl $ STR(_KERNEL_DS) ,%edxnt movl %edx,%dsnt movl %edx,%esnt保护完CPU的寄存器,就通过一条CALL指令调用do_IRQ

10、进入真正的中断服务程序中。这样CPU在进入中断服务程序do_IRQ时系统的堆栈情况如图2所示:从do_IRQ()返回到common_interrupt的jmp ret_from_intr处的地址orig_eax返回进程1被中断处的指令地址用户空间堆栈指针用户空间SS用户空间ESPEFLAGS用户空间CS用户空间EIP系统空间堆栈当前ESP中断号-256中断前的CPU寄存器ESEBX系统空间EIP图2 进入中断服务程序do_IR时的中断从图2可知,当系统处理完中断从do_IRQ()函数返回时将跳转到ret_from_intr处开始执行代码。(由于系统设计使得在中断服务过程中不会调用schedul

11、e()函数产生任务切换。因而中断服务结束后一定会返回到图2中的返回点)。orig_eax返回进程1被中断处的指令地址用户空间堆栈指针用户空间SS用户空间ESPEFLAGS用户空间CS用户空间EIP系统空间堆栈当前ESP中断号-256中断前的CPU寄存器ESEBX图3 中断返回后的堆栈其中的ret_from_intr处的代码如下:ret_from_intr: GET_CURRENT(%ebx)ret_from_exception: movl EFLAGS(%esp),%eax # mix EFLAGS and CS movb CS(%esp),%al testl $(VM_MASK | 3),%

12、eax # return to VM86 mode or non-supervisor? jne ret_from_sys_call jmp restore_all在上述代码中,系统首先取出当前进程(进程1)的task_struct结构指针放入ebx寄存器中。然后在判断中断是发生在用户空间还是系统空间,如果发生在系统空间,则直接跳转到restore_all处中断返回。由于本例中中断发生在进程1的用户空间中,因而程序跳转到ret_from_syscall处执行,该段代码如下:ret_from_sys_call: cli # need_resched and signals atomic test

13、 cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_returnrestore_all: RESTORE_ALL到达ret_from_syscall后,系统将判断当前进程(进程1)的need_resched字段值是否为零,如果非零则调用schedule()函数进行任务切换。在这里我们假设在中断服务程序中唤醒了进程2,则从中断服务程序do_IRQ返回时进程1的need_resched字段值即为1。因而系统将跳转到reschedule处运行,该段代码如下:reschedule: call SY

14、MBOL_NAME(schedule) # test jmp ret_from_sys_call由此可见系统在此处将直接调用schedule()函数进行进程切换。Schedule()函数的实现入下:asmlinkage void schedule(void) struct schedule_data * sched_data; struct task_struct *prev, *next, *p; struct list_head *tmp; int this_cpu, c; if (!current-active_mm) BUG();need_resched_back: prev = cu

15、rrent; this_cpu = prev-processor; if (unlikely(in_interrupt() printk(Scheduling in interruptn); BUG(); sched_data = & aligned_datathis_cpu.schedule_data; if (unlikely(prev-policy = SCHED_RR) if (!prev-counter) prev-counter = NICE_TO_TICKS(prev-nice); move_last_runqueue(prev); switch (prev-state) case TASK_INTERRUPTIBLE: if (signal_pend

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1