一、Linux与其它类Unix内核的比较:
1)单块结构的内核:由几个逻辑上独立的成分构成,单块结构,大多数据商用Unix变体也是单块结构;
2)编译并静态连接的传统Unix内核:Linux能自动按需动态地装载和卸载部分内核代码(模块),而传统Unix内核仅支持静态连接;
3)内核线程:Linux以一种十分有限的方式使用内核线程来周期性地执行几个内核函数,而一些Unix内核则本身被组织成一组内核线程;
4)多线程应用程序支持:Linux定义了自己的轻量级进程版本,并以此来实现对多线程应用程序的支持,而商用Unix则都是基于内核线程来作为多线程应用程序的执行环境;
5)抢占式内核:Linux2.6提供了“可抢占的内核”的编译选项,当采用这种编译方式来编译内核时,可以随意交错执行处于特权模式的执行流,而一些传统的、通用的Unix,如Solaris则是完全的抢占式内核;
6)多处理器支持:一些Unix内核变体都利用了多处理器系统,Linux2.6支持不同存储模式的对称多处理,不仅可以使用多处理器,同时每个处理器可以毫无区别地处理任何一个任务;
注:"对称多处理"(Symmetrical Multi-Processing)又叫SMP,是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构。
7)文件系统:Linux标准文件系统支持多种不同类型的文件系统,由于采用了面向对象虚拟文件系统技术,外部文件系统可以很容易移植到Linux内核上;
注:虚拟文件系统(VFS)是物理文件系统与服务之间的一个接口层,它对Linux的每个文件系统的所有细节进行抽象,使得不同的文件系统在Linux核心以 及系统中运行的其他进程看来,都是相同的。严格说来,VFS并不是一种实际的文件系统。它只存在于内存中,不存在于任何外存空间。VFS在系统启动时建 立,在系统关闭时消亡。
8)STREAMS:大部分Unix内核均包含STREAMS I/O子系统,作为编写设备驱动程序、终端驱动程序及网络协议的首选接口,但Linux无类似的子系统;
二、硬件依赖性:
Linux试图在硬件无关的源代码与硬件相关的源代码之间保持清晰的界限,为此,Linux为不同的硬件平台作了不同的支持,目前共对23种不同的硬件平台类型作了专门的支持。
三、操作系统基本概念:
当操作系统启动时,内核被装入到RAM中,内核中包含了系统运行所必须的很多核心过程。内核为系统中所有事情提供了主要功能,并决定高层软件的许多特性。
操作系统的两个主要目标:与硬件交互以及为运行在其上的应用程序提供执行环境。
多用户系统:
能并发和独立执行分别属于两个或多个用户的若干应用程序的计算机。“并发”意味着几个应用程序能同时处于活动状态并竞争各种资源;“独立”意味着每个应用程序能执行自己的任务,而无需考虑其他用户的应用程序在干些什么;
多用户操作系统必须包含的特点:
核实用户身份的认证机制;
防止有错误的应用程序妨碍到其它应用程序在系统中运行的保护机制;
防止有恶意用户程序干涉或窥视其它用户的活动的保护机制;
限制分配给每个用户的资源数的记账机制;
以上保护机制依赖与CPU特权模式相关的硬件保护机制。
用户和组:
所有的用户由一个唯一的用户标识符来标识。
为了实现资料的共享,引入用户组,组由唯一的用户组标识符来标识。
任何类Unix操作系统都有一个特殊的root用户,即超级用户,操作系统不对她使用通常的保护机制,可以访问系统中的任何一个文件,并干涉任何一个正在执行的用户程序活动。
进程:
程序执行的一个实例,一个运行程序的“执行上下文”。
Unix是具有抢占式进程的多处理器操作系统。
类Unix操作系统采用进程/内核模式,每个进程都自以为它是系统中唯一的进程,可以独占操作系统所提供的服务。只要进程发出系统调用,硬件就会把特权模式由用户态变成内核态,然后进程以非常有限的目的开始一个内核过程的执行。
内核体系结构:
大部分Unix内核是单块结构:每一个内核层都被集成到整个内核程序中,并代表当前进程在内核态下运行。
微内核操作系统只需要内核有一个很小的函数集,通常包括几个同步原语、一个简单的调度程序和进程间的通信机制。
微内核操作系统一般比单块内核的效率低,因此操作系统不同层次之间显式的消息传递要花费一定的代价。
微内核操作系统迫使系统程序员采用模块化方法,因为任何操作系统层都是一个相对独立的程序,这种程序必须通过定义明确而清晰的软件接口,以实现与其他层的交互,同时时方便移植。
微内核操作系统比单块内核更充分的利用了RAM。
Linux内核提供了模块。模块是一个目标文件,其代码可以在运行时链接到内核,或从内核上解除链接。这种目标代码通常由一组函数组成,用来实现文件系统、驱动程序或其它内核上层功能。
四、Unix文件系统概述:
文件:
Unix文件是以字节序列组成的信息载体,内核不解释文件的内容。
文件或目录名由除了“/”和“\0”之外的任意ASCII字符序列组成,通常不能超过255个字符。
当标识文件名时,“.”和“..”分别用来标识当前工作目录和父目录。
硬链接和软链接:
包含在目录中的文件名就是一个文件的硬链接,或简称链接。
软链接又称为符号链接,是短文件,这些文件包含有另一个文件的任意一个路径名。ln hf soucefile 为sourcefile 建立硬连接sf1
硬链接类似直接拷贝,删除原文件,硬链接还存在。软连接类似快捷方式,删除源文件,软连接失效。
ln -s sf soucefile 为sourcefile 建立软连接sf1
文件类型:
Unix文件可以是下列类型之一:
普通文件
目录
符号链接
面向块的设备文件
面向字符的设备文件
管道和命令管道
套接字(Socket)
文件描述符与索引节点:
除了设备文件盒特殊文件外,每个文件都由字符序列组成,文件内容不包含任何控制信息。
文件系统处理文件需要的所有信息包含在一个名为索引节点的数据结构中。
索引节点至少提供以下属性:
l 文件类型
l 与文件相关的硬链接个数
l 以字节为单位的文件长度
l 设备标识符(包含文件的设备的标识符)
l 在文件系统中识别文件的索引节点号
l 文件拥有者的UID
l 文件的用户组ID
l 几个时间戳,表示索引节点状态改变的时间、最后访问时间及最后修改时间
l 访问权限和文件模式
文件操作的系统调用:
当用户访问一个变通文件或目录文件的内容时,实际是访问硬件设备上的一些数据,因此,文件系统是硬盘分区物理组织的用户级视图。而由于处于用户态的进程不能直接与低层硬件交互,因此,所有实际的文件操作都必须在内核态下进行。
当几个进程同时打开一个文件时,文件系统给每个文件分配一个单独的打开文件对象以及单独的文件描述符。在这种情况下,Unix文件系统对进程在同一文件上发出的I/O操作之间不提供任何形式的同步机制。
对普通Unix文件,可以顺序访问,也可随机访问,而对设备文件和命名管道文件,通常只能顺序访问。
五、Unix内核概述:
Unix内核提供了应用程序可以运行的执行环境。因此,内核必须实现一组服务及相应的接口,应用程序使用这些接口,而且通常不会与硬件资源直接交互。
进程/内核模式:
所有标准的Unix内核都仅仅利用了内核态和用户态。
一个程序执行时,大部分时间都处在用户态下,只有需要内核所提供的服务时才切换到内核态。当内核满足了用户程序的请求后,便使程序回到用户态下。
内核本身不是进程,而是进程的管理者。
Unix系统包括几个称为内核线程的特权进程,它们通常在系统启动时创建,并以内核态运行在内核地址空间,一直处于活跃状态直到系统关闭。
进程实现:
每个进程由一个进程描述符表示。
当内核暂停一个进程的执行时,就把几个相关处理器寄存器的内容保存在进程描述符中。当内核决定恢复执行一个进程时,它用进程描述符中合适的字段来装载CPU寄存器,由于程序计数器中所存储的值指向下一条将要执行的指令,所以进程从它停止的地方恢复执行。
上文寄存器包括:程序计数器(PC)和栈指针(SP)寄存器,通用寄存器,浮点寄存器,包含CPU状态信息的处理器,跟踪进程对RAM访问的
Unix内核可以区分很多等待状态,这些等待状态由进程描述符队列实现。每个队列对应一组等待特定事件的进程。
可重入内核:
可重入,意味着若干进程可以同时在内核态下执行,但在每个处理器上只有一个进程在真正运行,其它则可能在等待执行或处于阻塞状态。
如果一个硬件中断发生,可重入内核能挂起当前正在执行的进程,即使这个进程处于内核态,这样可以提高发出中断的设备控制器的吞吐量。
进程地址空间:
在用户态下运行的进程涉及到私有栈、数据区和代码区。
在内核态下运行的进程,访问内核的数据区和代码区,但使用另外和私有栈。
如果一个程序由几个用户同时使用,则这个程序只被装入内存一次,其指令由所需要它的用户共享,当然,其数据不被共享。
进程间也能共享部分地址空间,以实现一种进程间的通信。
同步和临界区:
实现可重入内核需要利用同步机制,因为如果当内核控制路径对某个内核数据结构进行操作时被挂机,那么,其它内核控制路径就不应当再对该数据结构进行操作。
对全局变量的安全访问通过原子操作来保证。
如果内核支持抢占,如Linux,那么在应用同步机制时,确保进入临界区前禁止抢占,退出临界区时启用抢占。
信号量:
可以把信号量看成一个对象,其组成如下:
l 一个整数变量
l 一个等待进程的链表
l 两个原子方法:down()和up()
每个要保护的数据结构都有它自己的信号量,其初始值为1。当内核控制路径希望访问这个数据结构时,它在相应的信号量上执行down()方法,若信号量的当前值不是负数,则允许访问这个数据结构,否则,把执行内核控制路径的进程加入到这个信号量的链表并阻塞该进程。当另一个进程在那个信号量上执行up()方法是,允许信号量链表上的一个进程继续执行。
自旋锁:
自旋锁与信号量非常相似,但没有进程链表;当一个进程发现锁被另一个进程锁着时,它就不停的“旋转”,执行一个紧凑的循环指令直到锁打开。
自旋锁在单处理器环境下是无效的。因为:当内核控制路径试图访问一个上锁的数据结构时,它开始无休止循环,则内核控制路径可能因为正在修改受保护的数据结构而没有机会继续执行,也没有机会释放这个 自旋锁,最后的结果可能是系统挂起。
Linux使用一个名为init的特殊系统进程,它在系统初始化的时候被创建。当一个进程终止时,内核改变其所有现有子进程的进程描述符指针,使这些子进程成为init的孩子。Init监控所有子进程的执行,并且按常规发布wait4()系统调用,除掉所有僵死的进程。