zoukankan      html  css  js  c++  java
  • 怎么实现进程切换

    是什么

    进程是一个运行中的程序实体,拥有独立的地址空间和逻辑控制流。

    void sayHi()
    {
      printf("%s
    ", "Hello,World");
      return 0;
    }
    

    sayHi就是一个函数,它一旦运行起来,就是进程。

    独立的逻辑控制流,是说这个进程就像独占一个CPU一样。每个进程使用CPU的时间不是连续的,但它们的指令运行却是前后衔接的,不会受到其他进程的指令对它的指令和数据大的更改。

    运行起来

    进程,这里是指用户进程(区别于内核),处在特权级3。内核在特权级0。CPU从通电运行起,就处在特权级0。要运行用户进程,需要从特权级0转移到特权级3。

    CPU执行哪条指令,受cs:eip控制。有一个指令,既能够实现特权级从高向低转移,又能更新cs:eip。这个指令就是iretd

    执行第一个用户进程的方法是,把cs、eip、ss、esp等寄存器需要的值入栈,然后用irted出栈,用户进程就能运行起来了。示意代码如下。注意,下面的代码只是说明大概思路,不是可执行的代码。

    push		ss
    push		esp
    push		cs
    push		eip
    
    irted
    

    停下来

    操作系统要让一个CPU能运行多个进程。一个进程不能总是独占CPU,必须让它停下来,把CPU让给其他进程使用。

    时钟中断每隔一段时间就会停止当前进程,转移到执行中断例程。

    切换

    在中断例程中,我们可以为当前进程A建立一个”快照“,选择运行进程B。

    进程的”快照“,是把进程正在使用的数据、下一条要运行的指令等信息存储起来;然后选择另外一个进程,从存储设备中取出这个进程运行所需要的所有信息,最后运行这个进程。

    进程正在使用的数据,全部都在寄存器中,把寄存器中的数据存起来,就是为进程建立了快照。

    把数据存储到哪里呢?在汇编语言中,动态存储数据,我发现只有堆栈可以使用。进程的切换就是这样一个流程:

    1. 进程A正在运行,时钟中断发生,执行中断例程。
    2. 从TSS的esp0中获取进程A的堆栈栈顶,把esp指向这个栈顶。
    3. 把寄存器中的值都压入进程A的堆栈中。
    4. esp指向进程B的堆栈。调度程序就在这个步骤。
    5. 把TSS的esp0指向进程B的堆栈的最高地址处加4个字节。下一次中断发生时,TSS获取的esp0的值就是在这里获取的。
    6. B的堆栈出栈。
    7. 使用iretd出栈ss、esp、cs、eip,开始执行进程B的指令。

    堆栈转移

    从上面的切换过程,很容易看出,需要转移堆栈。

    第1步~~~第3步,堆栈从用户进程中的不知名堆栈转移到存储进程A数据的堆栈。这个堆栈,为进程建立快照使用。每个进程都有一个这样的堆栈。

    在第4步前后,都有一次堆栈切换:

    1. 前面,从A进程的堆栈切换到内核堆栈。进程调度程序很有可能会使用堆栈。如果仍然使用进程A的堆栈,会破坏A的堆栈,重新运行A时会有许多麻烦。
    2. 进程调度结束后,已经选择了进程B,需要从堆栈中恢复B的数据,于是把esp指向B的堆栈。

    进入内核后,我们切换过GDT和内核堆栈。当初我觉得没必要切换内核堆栈,现在终于发现了内核堆栈的作用。

    那个内核堆栈是这样建立的:先用0填充一段内存空间,比如4KB,然后在下面设置一个标号,这个标号就是内核堆栈。代码如下:

    StatckStrace		1024  resp		0
    TopStack:
    

    求道之人,不问寒暑。
  • 相关阅读:
    令人眼花缭乱的XP封面:)
    GT3.9.5中新增的DRS服务
    4月12日后WinXP系统将会强制下载SP2(zz)
    全球手机排名出炉 摩托三星西门子位置调整(zz)
    元宵佳节,悬谜竞猜
    Laszlo平台简介(zz)
    笔记本市场见闻
    最近Wallop好像较难上去啊
    Dell再次表示不采用AMD处理器(zz)
    Media Player Classic 6.4.8.3发布(zz)
  • 原文地址:https://www.cnblogs.com/chuganghong/p/14492695.html
Copyright © 2011-2022 走看看