linux内核综述

来源:互联网 发布:建立数据系统技术 编辑:程序博客网 时间:2024/06/02 02:01

    终于读完了Robert Love大师《linux内核设计与实现》,尽管有多处一知半解,但是仍然收获良多,不免想借机记下来,供以后参考。

    linux内核固然是个庞然大物,但是并非洪水猛兽,尽管其中充斥着各种精巧、复杂的数据结构以及别出心裁的算法,但是它仍然是有迹可循的。整个内核可以分为七个部分:进程管理、中断机制、同步机制、时钟管理、内存管理、文件管理、设备管理。下面将分别叙述。

    首先是进程管理。linux内核中为每个进程构造了大小为1.7KB的进程描述符,即驻留在内存中的结构体。结构体中包含准确无误地描述一个进程所需要的全部信息,包括进程状态、打开文件、内存地址空间等等重要信息。系统中所有的进程的进程描述符组织为一条循环双向链表。内核也为程序提供了一个获得当前正在运行的进程描述符的接口,它实现为一个宏。内核中将进程分为五种状态,分别是运行态(包括就绪态)、可中断阻塞态、不可中断阻塞态、僵死态、终止态。此处进程状态的划分与笔者在学习操作系统的时候稍有不同,操作系统学习的时候考虑的是内核管理的用户空间的进程在正常工作情况下的三种状态:运行态、就绪态、阻塞态,而没有考虑僵死态、终止态。内核中将进程组织为一颗进程树,init进程为树根,它在系统启动的时候创建,并且一直存在于系统中,它还负责收容孤儿进程以防系统中驻留僵死进程。linux通过系统调用clone实现fork函数,并且加入了写时复制机制,即在fork子进程之后如果什么多不做,并没有改变地址空间表示的内存区域的值,那么子进程和父进程是共享地址空间的,只有当子进程尝试改变内存或者加载新的程序(本质上也是改变内存)时,内核会拷贝一份父进程地址空间的副本,供子进程使用。进程运行完毕退出时,内核会停止进程的运行,但是不会马上回首进程占用的系统资源,比如进程描述符,知道进程的父进程调用wait等系统调用获取完子进程的终止状态之后内核才会清楚子进程占用的系统资源,这样做是为了提供子进程向上传递终止状态的机制。已经执行退出操作但是父进程没有获取子进程状态的进程会一直占用系统资源,这样的进程我们称之为僵死进程,一般来讲在编写多进程程序的时候需要特别注意,父进程要在子进程退出的时候获取子进程的终止状态,否则很容易就会造成系统资源泄漏。


    linux进程调度采用实时调度和分时调度两种方式,系统为进程设置了不同的优先级,成为nice值,nice值越高,优先级越低。每个优先级都有一个与之关联的优先级队列,系统在不同的优先级之间采用实时调度,保证高优先级的进程总是能够先运行,比如系统的交互式界面程序,以提供用户使用系统的请求响应速度。在同一优先级内部,系统采用分时调度,每个优先级相同的进程分配到一致大小的时间片,实行轮转调度。但是linux在轮转调度的基础上还加入了动态更改优先级的机制,如果某个进程总是把时间片用完才释放cpu,那么系统将会降低此进程的优先级,将它放到nice值更高的队列中去。用户空间的进程总是可以被抢占的,但是内核控件就不一定了,有时候系统在执行某些中断处理程序或者一些原子性操作,内核会暂时关闭中断,直到目标程序执行完毕。当某个进程被优先级更高的进程抢占的时候,内核会保存进程的上下文到进程描述符,以便下一次调度此进程时能够从正确的开始点执行。


    为了能够和用户空间进行通信,大部分时间都是在提供服务,内核提供了一组接口,供用户空间的程序调用,这组接口我们一般称之为系统调用。系统级程序开发人员通常会调用c库的高级库函数,高级库函数由c库函数实现,而在c库函数里面便调用了内核的系统调用。从库函数里面调用内核系统调用需要通过软中断实现。首先用户空间发起系统调用,库函数调用syscall函数设置正确的系统调用号以及参数,然后syscall根据系统调用号调用内核的函数实现系统调用,这样一组内核函数我们称之为系统调用处理程序。系统调用通常和每种操作系统有关,但是自从POSXI标准问世以后,linux内核提供的系统调用有了一个最小集规定。


进程和系统调用息息相关,系统调用和中断又密不可分,下一节笔者将会分享一些有关linux内核中断处理机制的心得。

0 0