Linux 内核综述

一、什么是Linux内核:

内核->操作系统中最重要的部分,内核将在系统引导时被装载进RAM,其中包含了很多关键的例程,以操作系统。内核是OS最为关键的部分,人们常将OS(操作系统)与内核等同。

内核,是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。

想象一下,拥有了内核的源程序对你来说意味着什么?我们可以了解系统是如何工作的。通过通读源代码,我们就可以了解系统的工作原理,这在Windows下简直是天方夜谭。我们还可以针对自己的情况,量体裁衣,定制适合自己的系统,这样就需要重新编译内核。

Linus Torvalds 开发了Linux ,其实他开发的就是内核,按内核官方主页的理解,这个内核就是Linux ;其它的扩展和应用都是围绕内核而展开的。所有Linux应用程序都会和内核发生直接或者间接的接触;比如硬件需要内核支持,网络的通信也需要内核支持;文件系统更需要内核支持... ...

 

二、为什么需要编译内核和管理内核
硬件是需要内核支持才行,有些硬件的支持没有被编入内核,这也需要我们重编内核;内核的包含的不仅仅是设备的驱动,还有其它的内容,比如网络协议的支持,防火墙的支持... ... 比如iptables的实现,有些功能是需要内核支持的,如果内核与iptables相关的内容没有被编入,iptables 相关的功能就无法实现。

Linux内核的源代码树基本是按照功能分类的。

kernel :基本功能

mm :内存管理

fs :虚拟文件系统。子目录中是各种文件系统相关代码

net :各种网络协议相关。

ipc :System V IPC(共享内存,信号量,消息)

init :内核启动相关,各种初始化

crypto :加密处理

block :块设备处理

drivers:各种设备驱动

sound :声音驱动

arch :CPU体系结构相关代码

include:各种头文件。内核编译时会用到

Linux内核的代码大约有一半是在drivers中。我们还可以从操作系统的角度把Linux内核的主要功能分成以下几类:

进程管理

内存管理

文件系统管理

网络管理

进程间通信管理

其他控制管理(进程调度,中断与延迟,时钟,系统调用,同步互斥)

 

三、内核重要功能:

3.1 进程管理

Linux中每一个进程都有一个独立的数据结构,用来保存该进程的ID,优先级,地址空间等信息。所谓进程管理,就是对该数据结构的管理。

进程ID是用来识别进程的编号,一个进程除了有进程ID,还有该进程所在组ID,会话ID。一般来说,拥有同一个控制终端的进程也同时拥有同一会话ID。

Linux中的进程一定是通过fork这个系统调用产生。调用fork的进程叫做父进程,生成的进程叫做子进程。一般来说,子进程在诞生之时,具有几乎与 父进程完全一样的数据结构,一样的进程空间,一样的作用目录,一样的信号设定状态等等,唯一不同的就是进程ID。fork完之后,子进程马上被加到调度队列中。fork出一个子进程如果除了ID和父进程不同外,完全一样的话就没什么意义了,所以一般在fork完后再调用一个exec系统调用,来加载一个新程序,赋予该子进程新任务。

exec所作的是对进程空间有关信息进行重新赋值,而文件,目录等不会变化。

exit系统调用可以结束一个进程的生命。释放所用空间,关闭文件等回收工作。 另外,由于子进程在被fork出来之后马上加入调度队列,而此时父进程和子进程又几乎一模一样,所以 fork完之后的下一动作是父进程的还是子进程的往往不确定。如果在父进程中调用了wait这个系统调用的话,父进程将会体现出父爱的伟大,让子进程优先 享有CPU,在子进程寿终正寝后,父进程才继续自己的路,并为已故子进程保留临终状态--正常死亡(正常结束),意外得病(异常结束),被人谋杀(被信号9干掉)等。

信号是Linux中进程间异步通信的一种机制。任何进程都可以发出信号。任何进程也都可以接受信号,而接受信号后的动作可以是默认动作,无视或指定动作三 种情况。不同种类的信号对应的默认动作往往也是不同的。无视就是不理它。指定动作就是指定一段代码,当相应信号来了就执行这段代码,停止当前动作,执行完 之后再回到原来的执行轨迹上,这个和中断很相似。

线程。Linux里的线程是模仿进程来实现的。所不同的是,线程间可以共享一个进程空间,还有就是多出了线程间关系信息。而从调度的角度看来,进程,线程 没有区别。程序中所调用的线程函数往往是POSIX线程库中的函数,该库中的函数再去调用Linux内核里的东西。

 

3.2内存管理

Linux中有两种内存管理,一种是物理内存管理,一种是虚拟内存管理。应用程序里所用到的内存一般都指虚拟内存。

物理内存管理。Linux内核是以页为单位对物理内存进行管理的。一页的大小根据不同的CPU是不同的。在Linux中对物理内存的管理用到了buddy 算法。通过buddy算法把相邻的空闲地址空间结合起来而形成一个比较大的地址空间。而有时Linux内核还需要用到比较小的地址空间,小到比一页还小, 此时Linux中用的是slab算法。

虚拟内存管理。虚拟内存的一个好处就是即使一个程序用到的物理内存是分散的,但从应用程序的角度依然可以连续的为其分配地址空间,这个地址空间就是虚拟地址空间而非物理地址空间。每个进程都有自己的虚拟地址空间,它们是彼此独立的,也就是说,不同的进程的虚拟地址空间可以有重复。这个特点的好处是显而易见的,进程可以不用考虑其他进程而自行决定对自己虚拟地址空间的分配和利用。一个进程的地址空间一般都分成代码段,数据段,堆,栈等不同的段,其中代码段是 具有写保护的。Linux中还有分页机制,虽然进程拥有一个庞大的的虚拟地址空间,但并不是每个虚拟地址都会有一个物理地址与其对应。只有在被用到时,才被分配到具体的物理地址,这种机制就是分页。通常,对利用频率比较低的虚拟地址空间,在被利用完之后,把它们所占用的物理地址释放,而被影射到swap分区上,该分区一般在硬盘上,这种操作是以页为基本单位进行的。另外,前面说的fork,由于子进程和父进程具有几乎完全一样的环境,因此不必在fork后 马上为子进程另行分配物理地址空间,而是和父进程共享同一物理地址空间,只有在其中一方需要进行写操作时才另外分配物理地址空间,这种机制就是Copy On Write。这是一个即省时又省空间的方法。

 

3.3 文件系统

在Linux面前,一切都可以看作文件来管理,无论是硬盘上的数据,设备,内存等统统如此。内核并不关心文件内的数据类型,而是由上面的应用程序来负责识别。Linux为每个文件分配一个inode,这是一个管理文件属性和定位文件物理位置的数据结构。所有文件都被组织在一个以/为根的目录中。

要想读写一个文件,首先要用open这个系统调用打开它。如果没有错误,该函数返回一个独一无二的大于2的正整数,称其为文件描述符。以后对文件的任何操 作都是通过这个文件描述符进行的。(一种情况例外,当一个进程在有打开文件的状态下,如果fork出一个子进程的话,该子进程会与父进程共享该文件描述 符,也就是说,子进程不用open而直接可以读写该文件。)0,1,2这三个文件描述符是被预先定义的特殊文件描述符,分别代表标准输入,标准输出,标准 错误输出。标准输入,标准输出一般都会被指定为终端,也可以指定到某一文件或管道等其他地方。

对文件的读写一般都不是直接对文件本身进行,而是中间要通过内存。如果要读一个文件,先把该文件的相关数据读到内存中,然后对内存进行读取;如果要修改某 文件,则先修改内存中的相关数据,文件本身并不能马上被修改,通常会有个延迟。由于cpu对内存的访问要快于对外部设备的访问,因此这种策略可以提高系统 响应速度。

Linux支持很多文件系统,除了标准的EXT2外,还支持VFAT,NFS等等。之所以可以支持众多文件系统,是因为在各种具体的文件系统上面有一个虚 拟文件系统(VFS)。有了VFS,对不同文件系统的操作就可以通过相同的接口进行了。

 

3.4 进程间通信

管道是Unix最古老的进程通信方式,父子进程间通过管道通信可以实现各种复杂的任务。非父子进程间的通信可以通过命名管道来实现。
socket也是进程间通信的手段之一,可以是同一个操作系统中的两个进程,也可以是不同计算机上的两个很遥远的进程。各种通信协议都可以用socket 来通信。Linux中的socket接口是在内核中实现的。主要的数据结构叫做socket buffer。为了使系统由很好的响应速度,采用尽量不复制通信数据的策略。受信时,通过指向接受数据的指针的移动来实现各层协议的解析;发信时,通过简 单的向要被发送的数据头部追加协议首部来实现。
System V IPC也是常用的进程通信方式。包括共享内存,信号量和消息对列。
FUTEX是Linux2.6开始使用的一种进程间通信方式。它是用于进程同步的。通过共享一个锁变量来实现共享资源的同步。它的特点是操作基本在用户空 间完成,无需进入内核态。

 

3.5 其他控制管理
进程调度。Linux内核提供的是一个多任务环境。在Linux上可以同时执行多个任务,但我们知道,实际上从微观上看,一个CPU在某一时刻只能执行一 个任务,但从宏观上我们的确看到了同时执行着多个任务。这个效果其实就是内核通过进程调度来实现的。就好像杂技演员只用两只手可以同时向空中抛出多个球一 样,并让所有球都能够保持在空中不落地。所不同的是,杂技演员手中的球往往是一样大小,一样分量的,因此它们从杂技演员手中到空中,再回到手中所用的时间 几乎是相同的。而Linux要处理的任务往往是不同分量的,所以每个任务所要占用的CPU时间就往往不等。这个分量的概念在这里叫做优先级,进程调度中加 入了优先级的概念,就复杂了。以后在详述吧。
中断和延迟。中断主要是在控制硬件系统的设备驱动中和时钟里发生。中断发生时,内核暂停当前任务的处理,进入相应的中断处理程序。中断处理程序结束后,内 核马上恢复之前的任务处理。为了提高中断处理的响应效果,同时也减轻由于中断处理而给整个系统造成的负担,Linux采用了一种叫做软中断的方法,通过这 种方法可以让一些不是很紧急的中断处理延迟进行。这种方式是不同于传统Unix中是所采用的中断优先级的方式的。
Linux有自己的时钟。每 隔一定时间就会捕捉一次硬件发生的时钟中断。时钟中断处理除了计时外,还负责处理各种定时任务,比如网络协议栈,设备驱动等。Linux在时钟处理上是非 常重视效率的。以后详述。
系统调用。系统调用是应用程序向内核请求服务的唯一手段。从应用程序的角度看,系统调用就是一些函数。一旦发生系统调用,应用程序自己的正在执行的代码暂 停,进入到内核中执行内核代码,这就是所谓的内核态。系统调用执行完后,恢复到应用程序原来的执行轨迹继续,所谓的用户态。如果系统调用执行失败,那么和 其他函数一样会返回一个错误。系统调用是一种很好的保护内核区代码和数据不受破坏的机制,因为应用程序要访问内核区时,必须通过系统调用进入内核态,而不 能自己直接访问内核区。
同步互斥。在Linux中往往同时存在着多个执行流,它们都有独立动作任务和环境。而无论硬件资源还是软件资源都是有限的,所以多个执行流之间难免会发生 如何协调的问题。为此,Linux准备了一些同步和互斥的方法。当多个进程请求同一资源时,可以用信号量。多个处理器的情况下,多个CPU之间的协调可以 用互斥锁。另外还有RCU,顺序锁等方法可用。

 

posted @ 2016-06-25 03:36  时光撒谎  阅读(408)  评论(0编辑  收藏  举报