Linux课程实验报告

Linux课程实验报告

1. 操作系统概述

  操作系统的发展经历了批处理,分时,实时,网络分布式这四个阶段,由最开始的提供简单服务到现在的提供一系列复杂的服务,操作系统变得越来越复杂。所以想要了解掌握操作系统,我们必须要有很好得脉络,更具这条脉络去学习理解现代操作系统。操作系统得种类有很多,我在此将结合开源的Linux os分析,了解Linux系统背后的设计思想和原理。
首先我们看一下操作系统的组织结构:
操作系统的分层组织
从这张图我们可以想到计算机中很著名的一句话:

计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

所以,不管是计算机的体系结构还是软件体系结构如操作系统,都是通过分层来组织实现。操作系统屏蔽硬件,同时通过系统调用命令接口来对应用层提供服务。
操作系统主要提供核心的进程,内存,文件,IO管理,如果将IO也看成一种特殊的文件,就分为进程,内存,文件管理三大模块,下面也将围绕这三部部分展开。

2. Linux os的进程管理

  进程管理是操作系统核心内容,首先要了解的就是进程的概念以及进程在os中是如何描述和创建的。
  进程是一种动态的概念,与之对应的是程序,程序是静态的代码和数据实体,而进程是程序的一次执行过程。现在,我们分析一下,程序是怎样的?怎么被组织起来的?首先,我们写好一份hello.c代码,经过预处理(hello.i),编译器的编译(hello.s),在经过汇编(hello.o),最后通过ld连接起来,被os执行。在这里,如果是静态链接的话,最终形成的exe文件就是可执行了,我们知道exe文件就是ELF文件格式,对于该文件,我们可以使用很多优秀的工具去分析,如readelf,ojbdump,size等,通过按ELF文件格式组织,os可以将该exe文件直接加载到内存,创建对应的进程,然后一条一条执行的指令,就可以完成程序的执行了。

现在的os都是支持多线程的,那么如何高效合理的管理进程就显得很重要。为了描述进程,os要维护一个庞大的数据结构task_struct如下:
image

现在有了这个task_struct,os就能够感知进程的所有信息,比如进程的状态,进程打开的文件,占用的内存等等。因此,创建进程的过程就是创建这样的一个数据结构。一个进程创建出来了,肯定是要来服务的,因此有进程的状态切换。典型的进程状态及其转换关系如下:
image

既然现在os支持多进程,必然涉及到进程的切换,如何切换调度进程,有常见的调度算法:FIFIO,RR,优先级,CFS,多级反馈队列等等。但是进程的切换离不开os的中断管理。
进程管理还要包括进程的同步管理,进程的死锁预防等,在此就不一一展开分析。

3. Linux os的内存管理

  由于os内存的管理并不是课程的重点,但是为了报告的完整性,还是要简单写一下。
  通过了进程的管理,os可以将程序与task_struct一一对应起来,实现进程的维护。那么,os是怎么将进程加载到内存,如何管理内存呢。os的内存管理也是经历了连续内存管理,非连续内存管理的过程。在最一开始,单一连续分配内存,来一个进程开辟多少内存,显然,这样内存支持不了几个进程同时运行,而后出现了基于交换覆盖的方式,但是需要程序员的参与,不太现实。基于程序的局部性原理,出现了请求分页式内存管理。该内存管理模型采用虚拟内存管理,对于32位系统,os为每一个进程提供了4G的逻辑地址空间,也就是exe文件中可以使用的地址范围,然后将该地址映射到物理内存上,当物理内存page不够用时,使用合适的页面调度算法进行调度。请求分页式就是加载程序的时候一开始只装入部分数据,等请求的页面缺失时再调度,这样可以使得一个进程在某一时刻运行时只占用少量的内存,从而os可以装入更多的程序。

4. Linux os的文件管理

  操作系统的文件系统是计算机组织,存取和保存信息的重要系统。在Linux文件系统的层次模型中,如图:
image

通过该图,我们可以看到Linux是采用虚拟文件系统,屏蔽了底层具体使用的文件系统(minix,Ext2...,FAT,device,etc),对上层用户进程提供了统一的操作接口,如read,write,open,close系统调用。
  现在谈论具体的文件系统结构是怎样的呢,文件系统结构包含了逻辑上和物理上两种结构,这和我们学的数据结构是一样的,因为文件本质也是一种数据结构~
通常在物理上,也即磁盘上的文件系统物理结构包含了如下:

  1. 引导控制块:os通过该数据结构,载入os
  2. 盘控制块
  3. 目录结构:组织文件需要
  4. FCB:文件系统感知文件的重要数据结构,就像进程和PCB的关系,表现在Linux中式inode结点数据结构
    在内存中,文件的逻辑结构包含有:
  5. 系统打开文件表
  6. 用户打开文件表
    image

现在我们知道了Linux文件系统的结构,也了解了其中的一些数据结构,我们现在举个例子来分析,分析一下读写文件的过程

  1. 用户进程通过open系统调用陷入内核,内核通过sys_open服务例程首先在高速缓冲中按名查找对应的inode结点,若找到,引用加一,若未找到则创建对应的这个inode;然后通过这个inode结点查找该文件是否存在,若存在返回文件描述符,若不存在则返回-1;
  2. 此时已经打开文件,拿到了fd,调用read和write分别由sys_readsys_write提供服务,这两个服务例程通过操作文件的定位指针,最终实现文件的读写。

Linux中有一句话:

一切皆文件

  因此,我这里将设备以及设备紧密相关的终端放在这个模块讲。设备是一种文件,那么是要该文件挂在在Linux文件系统了,os就可以访问。由于外设一般运行速度远远小于CPU,那么就会出现CPU等待外设的尴尬场面。举个例子,当CPU请求磁盘设备的一块数据时,请求发出,但是等磁盘真正准备好数据的时候,可能花费了很长一段时间(相对于高速的CPU),那么CPU在这段时间应该在什么呢?最简单的就是空转,这个模型就是最早的忙等待模型,CPU利用率太低。此次引入了中断管理
中断可以分为内部异常和外部中断,内部异常比如系统调用,可嵌套中断的处理过程如下:

image

回顾了中断和IO设备,我们再举一个使用I/O驱动磁盘的例子:

  1. 首先用户进程一样的发起open调用,os通过VFS打开设备,拿到fd;
  2. 用户通过fd想访问一个字节的数据,但是os无法直接操作外设,应为外设具体怎么实现是由厂家提供的,os只能通过相应的IO驱动控制外设;
  3. os控制IO设备的方式有很多,比如忙等待,DMA,通道,三种方式的效率越来越高,范式越越复杂。当需要读的命令到达设备,设备的设备控制器复杂取出要读的数据,在合适的时候送至内存,这样完成一次IO读。

5. Linux os的启动过程分析

当我把os的主要组成部门说完,考虑一下os是怎么启动起来的。

  1. 首先是内核引导阶段,进行硬件自检
  2. 在文件管理模块中,我们讲到了文件系统的引导模块,os会读入/boot下的内核文件
  3. start_kernel中通过汇编指令启动0号进程(init_task
  4. init_task完成启动的大量初始化任务,如CPU,内存,调度器等
  5. init_task调用如下两条语句执行fork出1,2号进程
    pid = kernel_thread(kernel_init, NULL, CLONE_FS);
    pid = kernel_thread(kerneladd, NULL, CLONE_FS);
    
  6. 至此0号进程变为idle进程,1号进程是所有用户态进程的父进程,2号进程是所有内核进程的父进程。

6. 影响应用程序性能表现的因素

当我们对Linux内核有了一定的了解后,我们考虑一个程序性能低下的原因。一方面归结于硬件原因,一方面是程序自身的原因。硬件方面

  1. CPU:CPU的处理速度决定了指令的执行速度
  2. 内存:内存的大小直接决定了os能装入多少(多大)的程序
  3. 磁盘:磁盘的读取速度限制了IO的访问速度,磁盘中加入缓存,或者更换为其他存取速度更快的设备也是很好的办法
  4. 网络:如果是网络程序,网络带宽就是程序的很大限制因素
    软件方面
  5. 软件是否复合代码规范,是否含有大量的代码冗余?能不能优化?
  6. 软件是否能利用的上局部性原理,例如我们在csapp中的实验一样,为什么矩阵按行优先访问速度快于按列优先访问的速度?
    当我们要去分析我们的程序具体由什么原因造成的时候,我们可以通过一些工具,常见的工具有top, ps, stat, upstat等等

6. 总结

  虽然Linux内核提供的功能就是这些,但是由于功能的不断完善扩充,内核也变得越来越庞大。Linus os内核分析是一件循序渐进的过程,不能指望一蹴而就。在学习分析Linux内核的过程,阅读Linux代码是最好最直接的放大,只有慢慢不断的积累,才能对内核在全局观上有自己的理解。
  同时也感谢孟宁和李春杰老师的细心讲解,使我获益匪浅,解决了我在学习深入Linux内核过程中的很多疑惑,谢谢两位老师这学期的耕耘与付出。

posted on 2021-05-10 14:00  southbridge  阅读(519)  评论(0)    收藏  举报

导航