zoukankan      html  css  js  c++  java
  • Linux进程切换代码分析

    朱宇轲 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

    这次我们来分析Linux中进程调度和切换的原理。

    关于Linux的进程调度,有很多相关的算法,比如先进先出、最短作业优先等,这个不是我们讨论的重点,对此有兴趣的同学可以翻阅《现代操作系统》中的第二章来对其进行深入的了解。

    在Linux中,进程的切换主要是通过调用schedule函数来实现的,shedule调用的时机为:

    • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();

    • 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
    • 用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

    也就是说,进程的切换主要是在中断处理过程中实现,此时是被动调度,一般的用户态进程走的都是这条路子;而对于内核线程来说,它可以在执行的过程中直接调用shedule函数,进行主动调度。

    进程的切换需要挂起一个进程,然后保存当前进程相关的上下文,之后进入新的进程,当回到之前的进程时再重新载入之前的上下文。这和中断的保存变量是不一样的:中断是发生在同一个进程之中,只不过由用户态进入了内核态,而进程切换是两个进程之间的变换,需要保存更多的信息。

    需要保存的进程上下文为:

    • 用户地址空间: 包括程序代码,数据,用户堆栈等

    • 控制信息 :进程描述符,内核堆栈等

    • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)

    接下来我们来简要分析一下shedule函数。

    进入函数中,可以看到这么一句:

    next = pick_next_task(rq, prev);
    

    这就是Linux中执行进程调度的函数,具体的细节予以封装,我们也不细深究。

    context_switch(rq, prev, next);
    

    这一句就是执行所谓的进程上下文切换,进入里面。

    switch_to(prev, next, prev);
    

    该函数执行了具体的切换操作,它的代码如下:

    "pushfl
    	"		/* save    flags */	
    "pushl %%ebp
    	"		/* save    EBP   */	
    "movl %%esp,%[prev_sp]
    	"	/* save    ESP   */ 
    "movl %[next_sp],%%esp
    	"	/* restore ESP   */ 
    "movl $1f,%[prev_ip]
    	"	/* save    EIP   */	
    "pushl %[next_ip]
    	"	/* restore EIP   */	
    __switch_canary					
    "jmp __switch_to
    "	/* regparm call  */	
    "1:	"						
    "popl %%ebp
    	"		/* restore EBP   */	
    "popfl
    "			/* restore flags */
    

    prev_sp、next_sp、prev_ip、next_ip是输入和输出参数,分别表示当前进程和下一个进程的ip与sp。

    这段代码其实应该也不是很难理解,就是将内核堆栈的ebp压栈,然后将next进程的sp放入内核堆栈的esp中,同时将变换前的esp保存到prev进程的sp中。之后将1处的代码段放入prev中,并将next的ip压栈。

    在这里需要注意的是,之后的jmp _switch_to会执行ret操作,此时就会出栈,将next的ip放入EIP里,接下来就会执行next进程的代码了。

    而通过movl $1f,%[prev_ip]语句,当我们再次回到prev进程的时候,就会执行代码段1之后的语句,返回之前存储的上下文(EBP、FLAGS等),重新执行prev进程。

    Linux的进程切换基本就是如此,下面是本次实验的截图:

    今天就讲到这里,谢谢大家。

  • 相关阅读:
    centos文件与权限
    python执行centos命令
    Centos下新建用户及修改用户目录
    微信现金红包 python
    图像直方图
    十三种基于直方图的图像全局二值化算法原理、实现、代码及效果。
    图像处理之常见二值化方法汇总
    OpenCV中对图像进行二值化的关键函数——cvThreshold()。
    cvLoadImage
    cvGet2D的用法
  • 原文地址:https://www.cnblogs.com/wickedpriest/p/4458199.html
Copyright © 2011-2022 走看看