课程学习总结报告

这门课程刚开始的时候,孟老师将Linux内核与其他各个模块的关系用非常简洁而又形象的图画表示出来,我认为,这张图对任何一个Linux小白,都有非常好的引导意义,是Linux内核模型大的框架,如下图所示。

 

 

经过大半个学期的学期,我也对Linux内核有了更多的认识。在我看来,作为操作系统最关键的一部分,Linux 内核是连接计算机软硬件的桥梁,起到了非常关键的承上启下作用。向上延伸,它提供了各式各样基础且关键的API接口,供上层库函数和程序通过系统调用来使用;向下延伸,它直接对接硬件设施。也就是说,Linux内核是一个“中介”,向“客户”(应用程序)提供服务,并将“客户”需求转化为“施工方”(硬件)能够理解的概念,以便项目落地。

对Linux内核模型再进一步了解,可以按照功能模块,再细分成进程管理、内存管理、虚拟文件系统、网络系统和进程间通信,如下图所示。

 

 

1、         进程管理:管理最核心的CPU资源,保证各个进程能够合理地利用CPU资源完成自身任务。

2、         内存管理:管理内存资源,使得内存被进程安全使用。

3、         虚拟文件系统:为方便对外设进行管理,将如硬盘、光盘等外设均抽象为虚拟文件,Linux内核提供诸如open、write、read等接口函数对其统一管理。

4、         网络系统:管理涉及网络操作的资源。

5、         进程间通信:为进程间交流资源提供渠道。

 

其中,进程管理为Linux内核最重要的部分,因为在操作系统中,进程是程序运行的动态实体,所有进程的工作开展都要依托于Linux内核的进程调度,其相互关系如下图所示。

 

 

 

 

 

 

 

 

 

 

最终程序以进程的形式得到CPU资源而运行,当其需要调动下层资源时,会向Linux操作系统内核发出系统调用请求,运行环境从用户态转向内核态,在某个时间节点,完成预期功能,再返回用户态继续运行。

 

以上即为基于本人的有限认识对Linux系统概念模型的总结,接下来以“读取文件”的一系列流程为例,进一步完善对模型的认识

 

操作系统读文件hello.txt,大体可以划分为如下流程:

 

 

1、         为读入文件做准备

在实例程序运行到 read 函数时,软中断int 0x80通过中断描述符表,跳到system_call,最后跳转至system_read去执行.

int sys_read(unsigned int fd, char * buf, int count) {
  ……
  if (fd >= NR_OPEN || count < 0 || !(file = curren t-> file[fd]))    
  ……
return file_read(inode, file, buf, count); }

 先检查输入参数的合理性,最后调用file_read函数读取文件。

2、         确定要文件内容的位置

int file_read(struct m_inode * inode, struct file * flip, char * buf, int count) { 
    …… 
    while(left) {
  if (nr = bmap(inode, (flip->f_pos)/BLOCK_SIZE))
           …… 
    } 
    ……
}

 在while循环中,根据数据的实际组织方式,确定文件内容在硬盘上的“块号”。

 

3、         将指定数据从硬盘读至系统缓冲区

以硬件的“块号”和“设备号”为依据,从硬盘中将hello.txt对应的数据块读入缓冲区。

int file_read(struct m_inode * inode, struct file * flip, char * buf, int count) { 
    …… 
  if(!(bh=bread(inode->i_dev, nr))) …… }

inode->i_dev为硬盘设备号,nr为具体块号,bread函数为读盘指令。一旦开始从硬盘读取数据,进程便转为不可中断的状态,直到数据全部读入缓冲区。

从中可以看出,上层程序读取文件时无需知晓任何具体硬件知识,由Linux内核完成涉及到底层的数据操作。

 

4、         将数据拷贝至程序运行的指定空间

先检测是否读完指定的数据量

int file_read(struct m_inode * inode, struct file * flip, char * buf, int count) { 
    …… 
  while(left) {
    ……
    nr = filp->f_pos % BLOCK_SIZE;
chars = MIN(BLOCK_SIZE - nr, left);
    ……
} …… }

 若没有读完,更新left的值,确定具体还有多少没有读完

int file_read(struct m_inode * inode, struct file * flip, char * buf, int count) { 
    …… 
  while(left) {
    ……
    filp->f_pos += chars;
left -= chars;
    ……
} …… }

最后把已经读出来的数据拷贝到用户空间

int file_read(struct m_inode * inode, struct file * flip, char * buf, int count) { 
    …… 
  while(left) {
    ……
    if (bh) {
      char *p =nr + bh->b_data;
      while(chars-->0)
        put_fs_byte(*(p++), buf++);
        brelse(bh);
    }
    ……
} …… }

 

int file_read(struct m_inode * inode, struct file * flip, char * buf, int count) { 
    …… 
  while(left) {
    ……
    filp->f_pos += chars;
left -= chars;
    ……
} …… }

通过file_read函数中的while(left){……}循环,完成hello.txt文件从硬盘到用户运行空间的读取。

 

课程总结:

在选这门课之前,我对Linux的认知仅限于一些诸如cd、ls等简单的指令,对操作系统的认知也仅限于操作系统相关教材中抽象的文字描述,其他的东西一窍不通。通过这个学期的学习,通过老师们对实际的代码的讲解,加深了我对操作系统的理解,大致知晓Linux是如何工作的,并且经过几次实际的实验操作,稍微有了跟踪、调试Linux系统的运行机制。

Linux作为一个广受欢迎并普遍应用于各行各业的操作系统,无疑是非常成功的。其内核模块也是相当复杂,不甚晦涩。虽有老师们的悉心讲解,但我感觉自己仅仅是摸到其新手门槛,要学习的知识浩如烟海,我了解到的仅是皮毛而已。

不过收获还有非常之多的,特别是通过几次实验的实际操作,我学会了如何调试内核,如何去逐步分析系统调用、如何去理解内核中的汇编代码等等。

感谢这门课程的学习,为我展示了计算机新世界的冰山一角!

 

posted @ 2020-07-04 15:04  lggang  阅读(398)  评论(0编辑  收藏  举报