Linux绪论

1.1 Linux文件系统概述

文件系统有以下几个特点:

1.1.1 文件

  Linux文件是以字节序列组成的信息载体,内核不解释文件的内容,从用户的观点来看,文件被组织在一个树结构的命名空间中。除了叶节点外,树的所有节点都表示目录名。

  Linux的每个进程都有一个当前工作目录,它属于进程执行上下文,标识出进程所用的当前目录。

 

1.1.2 硬链接和软链接

  包含在目录中的文件名就是一个文件的硬链接,或简称链接。在同一个目录或不同目录中,同一个文件可以有几个链接,因此对应几个文件名。

  Linux命令:

  $ ln p1 p2

  用来创建一个新的硬链接,即为由路径p1标识的文件创建一个路径名为p2的硬链接。但是硬链接有两方面的限制:

  • 不允许用户给目录创建硬链接,因为这可能把目录树变为环形图,从而就不可能通过名字定位一个文件。
  • 只有在同一个文件系统中的文件之间才能创建连接,这带来比较大的限制,因为现代Linux系统可能包含了多种文件系统,这些文件系统位于不同的磁盘或者分区,用户也许无法知道他们之间的物理划分。

  为了克服这些限制,引入了软链接,符号链接是端文件,这些文件包含有另一个文件的任一个路径名。路径名可以指向位于任意一个文件系统的任意文件或目录,甚至可以指向一个不存在的文件。

Unix命令:

  $ ln -s p1 p2

  创建一个路径名为p2的新软链接,p2指向路径名p1.当这个命令执行时,文件系统抽出p2的目录部分,并在那个创建一个名为p2的符号连接的新项。

 

1.1.3 文件类型

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

  • 普通文件
  • 目录
  • 符号链接
  • 面向块的设备文件
  • 面向字符的设备文件
  • 管道和命名管道
  • 套接字

1.1.4 文件描述符和索引节点

  Linux对文件的内容和描述文件的信息给出了清楚的区分。文件系统处理文件需要的所有信息包含在一个名为索引节点(inode)的数据结构中。每个文件都有自己的索引节点,文件系统用索引节点来标识文件。Linux索引节点至少包含如下属性:

  • 文件类型
  • 与文件相关的硬链接个数
  • 以字节为单位的文件长度
  • 设备标识符(即包含文件的设备的标识符)
  • 在文件系统中标志文件的索引节点号
  • 文件拥有者UID
  • 文件的用户组ID
  • 几个时间戳,表示索引节点状态改变的时间、最后访问时间以及最后修改时间
  • 访问的权限和文件模式

1.1.5 访问权限和文件模式

文件的潜在用户分为三种类型:

  • 作为文件所有者的身份
  • 同组用户,不包括所有者
  • 所有剩下的用户

  有三种类型的访问权限——读、写及执行每组用户都由这三种权限。还有三种附加的标记,即suid、sgid和sticky

 

1.1.6 文件操作的系统调用

打开文件,进程调用系统调用:

fd = open(path,flag,mode)

path:表示被打开文件的(相对或者绝对)路径

flag:指定文件打开的方式,也指定是否应当创建一个不存在的文件。

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

  这个系统调用创建一个“打开文件”对象,并返回所为文件描述符(file descriptor)的标识符,一个打开的对象包括:

  • 文件操作的一些数据结构,如指定文件打开方式的一组标志;表示文件当前位置的offset字段,从这个位置开始将进行下一个操作,等等。
  • 进程可以调用一些内核函数指针。
  • 文件描述符表示进程与打开文件之间的交互,而打开文件对象包含了与这种交互相关的数据。同一个打开文件对象也许由同一个进程中的几个文件描述符标识。
  • 几个进程也许同时打开同一文件。在这种情况下,文件系统给每个文件分配一个单独的打开文件对象以及单独的文件描述符。当这种情况发生时,Linux文件系统对进程在同一文件上发出的I/O操作质检部提供任何形式的同步机制。然而,有几个系统调用可用来让进程在整个文件或部分文件上对I/O操作实施同步。

访问打开的文件,对普通文件,可以顺序地访问,也可以随即地访问,而对设备文件和命名管道文件,通常只能顺序地访问,

newoffset = lseek(fd,offset,whence);

nread = read(fd,buf,count);

关闭文件

res = close(fd);

更名及删除文件

res=rename(oldpath,newpath);

res = unlink(pathname);

 

1.2 Linux内核概述

1.2.1 进程/内核模式

  内核本身并不是一个进程,而是进程的管理者。进程/内核模式假定:请求内核服务的进程使用所谓的系统调用的特殊编程机制。每个系统调用都设置了一组识别进程请求的参数,然后执行与硬件相关的CPU指令完成从用户态到内核态的转换。除用户进程之外,Linux系统还包括几个所谓的内核线程的特权进程,具有以下特点:

  • 他们以内核态运行在内核地址空间
  • 他们不与用户直接交互,因此不需要终端设备
  • 他们通常在系统启动时创建,然后一直处于活跃状态直到系统关闭

Linux内核做的工作远不止处理系统调用,实际上,可以有几种方式激活内核例程:

  • 进程调用系统调用
  • 正在执行进程的CPU发出一个异常信号,异常是一些反常情况。
  • 外围设备向CPU发出一个中断信号以通知一个事件的发生。
  • 内核线程被执行,因为内核线程运行在内核态,因此必须认为其响应程序是内核的一部分。

1.2.2 进程实现

  为了让内核管理进程,每个进程由一个进程描述符表示,这个描述符包含有关进程当前状态的信息。当内核暂停一个进程的执行时,就把几个相关处理器寄存器的内容保存在进程描述符中,这些寄存器包括:

  • 程序计数器(PC)和栈指针(SP)寄存器
  • 通用寄存器
  • 浮点寄存器
  • 包含CPU状态信息的处理器控制寄存器
  • 用来跟踪进程对RAM访问的内存管理寄存器

1.2.3 可重入内核

  所有的Unix内核都是可重入的,这意味着若干个进程可以同时在内核态下执行。

 

1.2.4 进程地址空间

  每个进程运行在它的私有地址空间。在用户态下运行的进程涉及到私有栈、数据区和代码区。当在内核态运行时,进程访问内核的数据区和代码区,但使用另外的私有栈。因为内核是可重入的,因此几个内核控制路径可以轮流执行,在这种情况下,每个内核控制路径都引用它自己的私有内核栈。

 

1.2.5 同步和临界区

  实现可重入内核需要利用同步机制:如果内核控制路径对某个内核数据结构进行操作时被挂起,NAMES,其他的内核控制路径就不应当再对该数据结构进行操作,除非它已被重新设置成一致性状态。

  

1.2.6 非抢占式内核

 

1.2.7 禁止中断

 

1.2.8 信号量

 

1.2.9 自旋锁

 

1.2.10 避免死锁

 

1.2.11 信号和进程间通信

  Linux信号提供了把系统实践报告给进程的一种机制。每个时间都有自己的信号编号,通常用一个符号常量来表示。有两种系统事件:

异步报告:

同步错误或异常

 

1.3 进程管理

 

1.3.1 僵死进程

 

1.3.2 进程组和登录会话

 

1.4 内存管理

1.4.1 虚拟内存

  所有新进的Linux系统度提供了一种有用的抽象,叫虚拟内存。虚拟内存作为一种逻辑层,处于应用程序的内存请求与硬件内存管理单元(MMU)之间。虚拟内存有很多用途和优点:

  • 若干个进程可以并发地执行
  • 应用程序所需内存大于可用物理内存时也可以运行
  • 程序只有部分代码装入内存时进程可以执行它
  • 允许每个进程访问可用物理内存的子集
  • 进程可以共享库函数或程序的一个单独内存映像
  • 程序是可重定位的,也就是说,可以吧程序放在物理内存的任何地方
  • 程序员可以编写与机器无关的代码,因为他们不必关心有关物理内存的组织结构

  虚拟内存子系统的主要成分是虚拟地址空间的概念。进程所用的一组内存地址不同于物理内存地址,当进程使用一个虚拟地址时,内核和MMU协同定位器在内存中的实际物理位置。

 

1.4.2 随机访问存储器RAM的使用

  所有的Linux操作系统都将RAM毫无疑问地划分为两部分,其中若干兆字节专门用于存放内核映像。RAM的其余部分通常由虚拟内存系统来管理,并且用在以下三种可能的方面:

  • 满足内核对缓冲区、描述符及其他动态内核数据的请求
  • 满足进程对一般内存区的请求及对文件内存映射的请求
  • 借助于高速缓存从磁盘及其他缓冲设备获得较好的性

 

1.4.3 内核内存分配器

  内核内存分配器是一个子系统,它试图满足系统中所有部分对内存的请求。其中一些请求来自内核其他子系统,他们需要一些内核使用的内存,还有一些请求来自于用户程序的系统调用,用来增加用户进程的地址空间。一个好的KMA应该具有下列特点:

  • 必须快。实际上,这是最重要的属性,因为它由所有的内核子系统调用。
  • 必须把内存的浪费减到最少
  • 必须努力减轻内存的碎片问题
  • 必须能与其他内存管理子系统合作,以便借用和释放页框。

  基于各种不同的算法计数,已经提出了几种KMA,包括:

  • 资源图分配算法
  • 2的幂次方空闲链表
  • McKusick-Karels分配算法
  • 伙伴系统
  • Mach的区域分配算法
  • Dynix分配算法
  • Solaris的slab算法

1.4.4 进程虚拟地址空间处理

  进程虚拟地址空间包括了进程可以引用的所有虚拟内存地址。内核通常用一组内存区描述符描述进程虚拟地址空间。内存分配给进程的虚拟地址空间由以下内存区组成:

  • 程序的可执行代码
  • 程序的初始化数据
  • 程序的未初始化数据
  • 初始程序栈
  • 所需共享库的可执行代码和数据
  • 堆(由程序动态请求的内存)

  所有现代Linux操作系统都采用了所谓请求调页的内存分配策略。有了请求调页,进程可以在她的页还没有在内存时就可以执行。当进程访问一个不存在的页时,MMU产生一个异常;异常处理程序找到受影响的内存区,分配一个空闲的页,并用适当的数据把它初始化。同理,当进程通过调用malloc()或brk()系统调用动态地请求内存时,内核仅仅修改进程的堆内存去的大小。只有试图引用进程的虚拟内存地址而产生异常时,才给进程分配页框。

 

posted @ 2016-08-24 13:48  pingfandfy  阅读(376)  评论(0编辑  收藏  举报