首页 | Linux 基础 | 资讯动态 | Linux 应用 | Linux 服务器 | Linux 开发 | Linux 安全 | 专题 | 联盟论坛
  当前位置:主页>Linux 开发>linux 内核>文章内容
深入学习LINUX内核之七(图文讲解)
来源:http://www.unix5.com 作者:riechelr_hl 发布时间:2008-04-15  



此后系统设置新任务的代码和资料段基址、限长,並复制当前行程记忆体分页管理的页表。注意,此时系统並不为新的行程分配实际的实体记忆体页面,而是让它共用其父行程的记忆体页面。只有当父行程或新行程中任意一个有写记忆体操作时,系统才会为执行写操作的行程分配相关的独自使用的记忆体页面。这种处理方式称为写时复制(Copy On Write)技术。

随后,如果父行程中有档案是打的,则应将对应档案的打开次数增加1。接著在GDT中设置新任务的TSS和LDT描述符项,其中基底位址资讯指向新行程任务结构中的tss和ldt。最后再将新任务设置成可执行状态並返回新行程号。

另外请注意,建立一个新的子行程和载入执行一个执行程式档是两个不同的概念。当建立子行程时,它完全复制了父行程代码和资料区,並会在其中执行子行程部分的代码。而执行区块装置上的一个程式时,一般是在子行程中执行exec( )系统呼叫来操作的。在进入exec( )后,子行程原来的代码和资料区就会被清掉(释放) 。待该子行程开始执行新程式时,由於此时內核还沒有从区块装置上载入该程式的代码,CPU就会立刻產生內码表面不存在的異常(Fault) ,此时记忆体管理程式就会从区块装置上载入相应的內码表面,然后CPU又重新执
行引起異常的指令,到此时新程式的代码才真正开始室执行。


5.7.5行程调度

內核中的调度程式用於选择系统中下一个要执行的行程。这种选择执行机制是多工作业系统的基础。调度程式可以看作为在所有处於执行状态的行程之间分配CPU执行时间的管理代码。由前面描述可知,Linux行程是抢佔式的,但被抢佔的行程仍然处於TASK_RUNNING状态,只是暂时沒有被CPU执行。行程的抢佔发生在行程处於用戶态执行阶段,在內核态执行时是不能被抢佔的。

为了能让行程有效地使用系统资源,又能使行程有较快的回应时问,就需要对行程的切换调度採用一定的调度策略。在Linux 0.12中採用了基於优先顺序排队的调度策略。

调度程式
schedule ( )函数首先扫描任务阵列。透过比较每个就绪态(TASK_RUNNING)任务的执行时间递減滴答计数counter的值来确定当前哪个行程执行的时间最少。哪一个的值大,就表示执行时间还不长,于是就选中该行程,並使用任务切換巨集函数切換到该行程执行。

如果此时所有处于TASK_RUNNING状态行程的时间片都已经用完,系统就会根据每个行程的优先权值priority,对系统中所有行程(包括正在睡眠的行程)重新计算每个任务需要执行的时间片值counter。计算的公式是:



这样对于正在睡眠的行程当它们被唤醒时就具有较高的时间片counter值。然后schedule ( )函数重新扫描任务阵列中所有处于TASK_RUNNING状态,重复上述过程,直到选择出一个行程为止。最后呼叫switch_to( )执行实际的行程切換操作。

如果此时沒有其他行程可执行,系统就会选择行程0执行,对於Linux 0.12来說,行程0会呼叫pause( )把自己置为可中断的睡眠状态並再次呼叫schedule( )。不过在调度行程执行时,schedule( )並>不在意行程0处於什麼状态。只要系统空闲就调度行程0执行。


行程切换
每当选择出一个新的可执行行程时,schedule( )函数就会呼叫定义在include/asm/system.h中的switch_to ( )巨集执行实际行程切換操作。该巨集会把CPU的当前行程状态(上下文)替換成新行程的状态。在进行切換之前,switch_to ( )首先检查要切換到的行程是否就是当前行程,如果是则什麼也不做,直接退出。否则就首先把內核全域变数current置为新任务的指标,然后长跳转到新任务的任务状态段TSS组成的位址处,造成CPU执行任务切換操作。此时CPU会把其所有寄存器的状态保存到当前任务寄存器TR中TSS段选择符所指向的当前行
程任务资料结构的tss结构中,然后把新任务状态段选择符所指向的新任务资料结构中tss结构中的寄存器资讯恢复到CPU中,统就正式开始执行新切換的任务了。这个过程可参见图5-23所示。






5.7.6终止行程

当一个行程结束了执行或在半途中终止了执行,那么內核就需要释放该行程所佔用的系统资源。这包括行程执行时打开的档案、申请的记忆体等。

当一个用户程式呼叫exit ( )系统呼叫时,就会执行內核函数do_exit ( )。该函数会首先释放行程代码段和资料段佔用的记忆体页面,关闭行程打开着的所有档,对行程使用的当前工作目錄、根目錄和执行程式的i节点进行同步操作。如果行程有子行程,则让init行程作为其所有子行程的父行程。如果行程是一个会话头行程并且有控制终端,则释放控制终端,並向属于该会话的所有行程发送掛断信号SIGHUP,这通常会终止该会话中的所有行程。然后把行程状态置为僵死状态TASK_ZOMBIE。並向其原父行程发送SIGCHLD信号,通知其某个子行程已经终止,最后do_exit ( )呼叫调度函数去执行其它行程。由此可见在行程被终止时,它的任务资料结构仍然保留著。因为其父行程还需要使用其中的资讯。

在子行程在执行期间,父行程通常使用wait ( )或waitpid ( )函数等待其某个子行程终止。当等待的子行程被终止並处於僵死状态时,父行程就会把子行程执行所使用的时间累加到自己行程中。最终释放已终止子行程任务资料结构所佔用的记忆体页面,並置空子行程在任务阵列中佔用的指标项。

5.8 Linux系统中堆栈的使用方法

本节內容概要描述了Linux內核从开机引导到系统正常执行过程中对堆栈的使用方式。这部分內容的說明与內核代码关系比较密切,可以先跳过。在开始閱读相应代码时再回来仔细研究。

Linux 0.12系统中共使用了四种堆栈。一种是系统开机初始化时临时使用的堆栈;一种己进入保护模式之后提供內核程式初始化使用的堆栈,位於內核代码位址空间固定位置处。该堆栈也是后来任务0使用的用戶态堆栈;另一种是每个任务透过系统呼叫,执行內核程式时使用的堆栈;我们称之为任务的內核态堆栈。每个任务都有自己独立的內核态堆栈;最后一种是任务在用戶态执行的堆栈,位於任务(行程)逻辑位址空间近末端处。

使用多个堆栈或在不同情況下使用不同堆栈的主要原因有两个。首先是由於从真实模式进入保护模式,使得CPU对记忆体定址存取方式发生了变化,因此需要重新调整设置堆栈区域。另外,为了解決不同CPU特权级共用使用堆栈带来的保护问题,执行0级的內核代码和执行3级的用戶代码需要使用不同的堆栈。当一个任务进入內核态执行时,就会使用其TSS段中给出的特权级0的堆栈指标tss.ss ( )、tss.esp( ),即内核堆栈。原用户堆栈指标会被保存在内核堆栈中。而当初从内核态返回用户态时,就会恢复使用用户态的堆栈。下面分别对它们进行说明。
共12页: 上一页 [1] [2] [3] [4] [5] 6 [7] [8] [9] [10] [11] [12] 下一页
 
如果您对本文有任何疑问或者建议,请到论坛讨论区发表您的意见: >> 论坛入口
[收藏] [推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
  热点文章
·使用 Linux 系统调用的内核命令
·Linux 2.6.11内核文件IO系统调用
·Linux操作系统的源代码目录树结
·Linux用户态与内核态的交互讲解
·Linux内核对I/O端口的管理实现(
·深入分析 Linux操作系统的内核链
·Linux内核可装载模块对设备驱动
·概述Linux系统的驱动框架及驱动
·详解Linux 2.6内核新文件系统变
·Linux系统可卸载内核模块完全指
·FreeBSD手册讲解(一)--配置FreeB
·编译Linux操作系统的内核讲解
  相关文章
·深入学习LINUX内核之六(图文讲解
·深入学习LINUX内核之五(图文讲解
·深入学习LINUX内核之四(图文讲解
·Linux系统内核漏洞分析
·深入学习LINUX内核之三(图文讲解
·如何在Linux内核中的实现SYN Coo
·深入学习LINUX内核之二(图文讲解
·简析Linux与FreeBSD的syscall
·深入学习Linux内核文档一(图文讲
·Linux操作系统“警惕”内核汉化
·Linux操作系统核心的汉字显示机
·如何利用异常表处理Linux内核态

本站信息源至:互联网络,均为学习,交流所用,如有版权问题,请联系我们.
站长QQ:397422079 E_mail:riechelr_hl@unix5.com
转载本站内容请注明原作者名.谢谢!