《深入理解Linux内核 第一章》学习笔记

posted in: LINUX | 0

第一章 绪论

Unix文件系统概述

文件

  • Unix文件是以字节序列组成的信息载体,内核不解释文件的内容。
  • 文件或目录名由除“/”和空字符“\0”之外的任意ASCII字符组成。
  • 大多数文件系统对文件名长度都有限制,通常不能超过255个字符。

 

硬链接和软连接

  • 包含在目录中的文件名就是一个文件的硬链接,简称链接。
  • 在同一个目录或不同的目录中,同一个文件可以有几个链接:
ln p1 p2
  • 硬链接有以下限制:

不允许用户给目录创建硬链接

只有在同一文件系统中的文件之间才能创建链接

  • 软连接又叫符号链接,符号链接是短文件,这些文件包含另一个文件的任意一个路径名。
ln -s p1 p2

 

文件类型

Unix文件可以是下列类型之一:

  1. 普通文件
  2. 目录
  3. 符号链接
  4. 面向块的设备文件
  5. 面向字符的设备文件
  6. 管道和命名管道
  7. 套接字

 

文件描述符和索引节点

  • 除了设备文件和特殊文件系统,每个文件都有字符序列组成。
  • 文件系统处理文件需要的所有信息包含在一个名为索引节点的数据结构中。每个文件都有自己的索引节点,文件系统用索引节点来标示文件。

 

访问权限和文件模式

  • 文件的潜在用户分为三种类型:
  1. 作为文件的所有者用户
  2. 同组用户,不包含所有者
  3. 所有剩下的用户

每种类型有三种访问权限——读、写、执行。

  • 三种附加的标记
  1. suid:进程执行一个文件时通常需要保持进程拥有者的UID
  2. sgid:进程执行一个文件时保持进程组的用户组ID
  3. sticky:设置sticky的标志位可执行文件相当于向内核发出一个请求

 

文件操作的系统调用

打开文件
  • 进程只能访问打开的文件,为了打开一个文件,进程调用系统调用
fd = fopen(path, flag, mode);

path:被打开文件的路径

flag:表示文件的打开方式

mode:指定新创建文件的访问权限

  • 一个打开的文件对象包括:
  1. 文件操作的一些数据结构
  2. 进程可以调用的一些内核函数指针
访问打开的文件

对于普通的Unix文件,可以顺序的访问,也可以随机的访问,而对设备文件和命名管道文件,通常只能顺序的访问。

nowoffset = lseek(fd, offset, whence);

fd:表示打开的文件描述符

offset:一个有符号的整数值,用来计算文件指针的新位置

whence:指定文件指针新位置的计算方式:可以使offset加0,表示文件指针从文件头移动;也可以offset加文件指针的当前位置,表示文件指针从当前位置移动;还可以是offset加文件最后一个字节的位置,表示文件指针从文件的末尾开始移动

更名以及删除文件
  • 更名
res = rename(oldpath, newpath);
  • 减少文件链接数,删除了相应的目录项。只有当链接数为0的时候,文件才被真正的删除
res = unlink(pathname);

 

Unix内核概述

进程/内核模式

内核本身不是一个进程,而是进程管理者。

Unix系统还包含几个所谓的内核线程的特权进程,他们有如下特点:

  1. 他们以内核态运行在内核地址空间;
  2. 他们不与用户直接交互,因此不需要终端设备;
  3. 他们通常在系统启动时创建,然后一直处于活跃状态直到系统关闭;
  • 激活内核例程的方式
  1. 进程调用系统调用
  2. 正在执行的CPU发出一个异常
  3. 外围设备向CPU发出中断信号以通知一个事件的发生
  4. 内个线程被执行

进程

当内核暂停一个进程的执行时,就把几个相关的处理器的内容保存在进程描述符中,这些寄存器包括:

  1. 程序计数器和栈指针寄存器
  2. 通用寄存器
  3. 浮点寄存器
  4. 包含CPU状态的处理器控制寄存器
  5. 用来跟踪进程对RAM访问的内存管理寄存器

可重入内核

内核控制路径:表示内核处理系统调用,异常或中断所有支线的指令序列。

进程地址空间

每个进程运行在它的私有地址空间,在用户态下运行的进程涉及到私有栈,数据区,代码区。当在内核态运行时,进程访问内核的数据区和代码区,但使用另外的私有栈。

非抢占式内核

当进程在内核态执行时,他不能被任意挂起,也不能被另一个进程替代。

禁止中断

在进入一个临界区之前禁止所有硬件中断,离开后再重新启用中断。

信号量

所有内核线程在试图访问这个数据结构之前,都要检查这个信号量。可以把每个信号看成一个对象。其组成如下:

  1. 一个整数变量
  2. 一个等待进程的链表
  3. 两个原子方法:down()和up()
自旋锁

自旋锁与信号量相似,但没有进程链表,当一个进程发现锁被另一个进程锁着时,它就不停的旋转,执行一个紧凑的循环指令直到锁打开。

信号和进程间通信

Unix信号提供了把系统事件报告给进程的一种机制。

一般来说,进程可以以两种方式对接收到的信号做出反应:

  1. 忽略该信号
  2. 异步的执行一个指定的过程

如果进程不指定选择的操作,内核就根据信号的编号执行一个默认的操作。五种默认操作是

  1. 终止进程
  2. 将执行上下文的进程的地址空间的内容写入一个文件,并终止进程。
  3. 忽略该信号
  4. 挂起进程
  5. 如果进程曾被暂停,则恢复他的执行。

信号量、消息队列以及共享内存统称为System V IPC。

进程要获得一个资源,可以调用shmget()、semget()、msgget()系统调用。

共享内存为进程之间交换和共享数据提供了最快的方式。

进程管理

fork():创建一个新进程

_exit():终止一个进程

exec():装入一个新程序

僵死进程

wait4()系统调用允许进程等待,直到其中的一个子进程结束,它返回已终止子进程的进程标识符。

僵死进程的特殊状态是为了表示终止的进程:父进程执行完wait4()系统调用之前,进程就一直停留在那种状态。

解决办法是使用一个名为init的特殊系统进程,他在系统初始化的时候被创建,当一个进程终止时,内核改变其所有现有子进程的描述符指针,使这些子进程成为init的孩子。init监控所有的子进程执行,并且按照常规发布wait4()系统调用,其副作用就是除掉所有僵死进程。

进程组和登录会话

现代Unix操作系统引入进程组的概念,以表示一种作业的抽象。

 

内存管理

虚拟内存

所有最近的Unix系统都提供了一种有用的抽象,叫做虚拟内存。

虚拟随机访问存储器

所有的unix操作系统都将RAM毫无疑义的分为两部分:

专门存储内核映像

由虚拟内存系统处理

内核内存分配器

内核内存分配器是一个子系统,它试图满足系统中所有部分对内存的请求。

进程虚拟地址空间处理

进程的虚拟地址空间包括了进程可以引用的所有虚拟内存地址。

高速缓存

物理内存的一大优势就是用作磁盘和其他块设备的高速缓存。

 

设备驱动程序

内核通过设备驱动程序与I/O设备交互。