课程学习报告

目录
  • Linux内核基本功能
    • 1. 进程管理
      • Linux内核中有关进程的部分数据结构:
    • 2. 文件系统
      • 文件打开:
      • 文件关闭
      • 读文件流程
      • 虚拟文件系统
    • 3. 中断和系统调用
      • 中断的处理过程:
      • 系统调用的过程:
    • 4. 总结

Linux内核基本功能

Linux内核主要由以下几个功能:进程管理、文件系统、IO体系结构和设备驱动程序、内存管理等等。
课程学习报告_第1张图片
下面对Linux的各个功能进行简单的介绍。

  1. 进程管理:进程管理是linux内核中最重要的部分,它保证了程序的正常执行。 在Linux中, 进程是系统资源分配的基本单位,也是使用CPU运行的基本调度单位。它实现了对进程的控制和调度。

  2. 文件系统:在Linux中,一切都是文件,通过对文件的定义和操作来控制设备的执行和数据的存储。并且使用VFS虚拟文件系统,实现对多种文件系统的兼容。

  3. IO体系结构和设备驱动程序:在Linux中,驱动是应用软件和硬件的桥梁,应用程序只需要调用系统软件的应用编程接口,就可以让相应的硬件完成工作,通过设备驱动程序的定义和运行实现了对IO设备操作的控制。

  4. 内存管理:内存管理子系统可能是linux内核中最为复杂的一个子系统,其支持的功能需求众多,如页面映射、页面分配、页面回收、页面交换等,而且对性能也有很高的要求。

1. 进程管理

一个进程的上下文(context)包括进程的状态、有关变量和数据结构的值、机器寄存器的值和PCB以及有关程序、数据等。

一个进程的执行是在进程的上下文中执行。

当正在执行的进程由于某种原因要让出处理机时,系统要做进程上下文切换,以使另一个进程得以执行。

当进行上下文切换时系统要首先检查是否允许做上下文切换(在有些情况下,上下文切换是不允许的,例如系统正在执行某个不允许中断的原语时)。然后,系统要保留有关被切换进程的足够信息,以便以后切换回该进程时,顺利恢复该进程的执行。在系统保留了CPU现场之后,调度程序选择一个新的处于就绪状态的进程、并装配该进程的上下文,使CPU的控制权掌握在被选中进程手中。

Linux内核中有关进程的部分数据结构:

struct task_struct {
......
 /* 进程状态 */
    volatilelongstate;
 /* 指向内核栈 */
    void*stack;
 /* 用于加入进程链表 */
structlist_head tasks;
   ......
 /* 指向该进程的内存区描述符 */
structmm_struct*mm,*active_mm;
......
 /* 进程ID,每个进程(线程)的PID都不同 */
    pid_t pid;
 /* 线程组ID,同一个线程组拥有相同的pid,与领头线程(该组中第一个轻量级进程)pid一致,保存在tgid中,线程组领头线程的pid和tgid相同 */
    pid_t tgid;
  /* 用于连接到PID、TGID、PGRP、SESSION哈希表 */
structpid_link pids[PIDTYPE_MAX];
......
  /* 指向创建其的父进程,如果其父进程不存在,则指向init进程 */
    structtask_struct __rcu *real_parent;
  /* 指向当前的父进程,通常与real_parent一致 */
    structtask_struct __rcu *parent;
  /* 子进程链表 */
    structlist_head children;
  /* 兄弟进程链表 */
    structlist_head sibling;
  /* 线程组领头线程指针 */
    structtask_struct*group_leader;
  /* 在进程切换时保存硬件上下文(硬件上下文一共保存在2个地方: thread_struct(保存大部分CPU寄存器值,包括内核态堆栈栈顶地址和IO许可权限位),内核栈(保存eax,ebx,ecx,edx等通用寄存器值)) */
    structthread_struct thread;
  /* 当前目录 */
    structfs_struct*fs;
 /* 指向文件描述符,该进程所有打开的文件会在这里面的一个指针数组里 */
structfiles_struct*files;
......
/*信号描述符,用于跟踪共享挂起信号队列,被属于同一线程组的所有进程共享,也就是同一线程组的线程此指针指向同一个信号描述符 */
structsignal_struct*signal;
/*信号处理函数描述符 */
structsighand_struct*sighand;
......
}

2. 文件系统

在LINUX系统中有一个重要的概念:一切都是文件。 其实这是UNIX哲学的一个体现,而Linux是重写UNIX而来,所以这个概念也就传承了下来。在UNIX系统中,把一切资源都看作是文件,包括硬件设备。UNIX系统把每个硬件都看成是一个文件,通常称为设备文件,这样用户就可以用读写文件的方式实现对硬件的访问。这样带来优势也是显而易见的:UNIX 权限模型也是围绕文件的概念来建立的,所以对设备也就可以同样处理了。

文件打开:

应用程序对open ( )的调用将引起内核调用服务例程sys_open ( )函数,该函数接收的参数为:要打开文件的路径名和访问模式等;
该系统调用成功后将返回一个文件描述符,也就是文件对象指针数组的一个索引;
系统调用不成功时返回-1。

文件关闭

用户程序通过close ( )系统调用关闭打开的文件,该函数接收的参数为要关闭文件的文件描述符。
内核服务例程为sys_close ( )函数。

读文件流程

进程调用库函数向内核发起读文件请求;
内核通过检查进程的文件描述符定位到虚拟文件系统的已打开文件列表表项;
调用该文件可用的系统调用函数read()。read()函数通过文件表项链接到目录项模块,根据传入的文件路径,在目录项模块中检索,找到该文件的inode;
在inode中,通过文件内容偏移量计算出要读取的页;
通过inode找到文件对应的address_space;
在address_space中访问该文件的页缓存树,查找对应的页缓存结点:
如果页缓存命中,那么直接返回文件内容;
如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页;重新进行第6步查找页缓存;
文件内容读取成功。

虚拟文件系统

是 Linux 内核中的一个软件层,用于给用户空间的程序提供文件系统接口;
同时,它也提供了内核中的一个抽象功能,允许不同的文件系统共存。
系统中所有的文件系统不但依赖 VFS 共存,而且也依靠 VFS 协同工作。
为了能够支持各种实际文件系统,VFS 定义了所有文件系统都支持的基本的、概念上的接口和数据 结构;
同时实际文件系统也提供 VFS 所期望的抽象接口和数据结构,将自身的诸如文件、目录等概念在形式 上与VFS的定义保持一致。一个实际的文件系统想要被 Linux 支持,就必须提供一个符合VFS标准 的接口,才能与 VFS 协同工作。实际文件系统在统一的接口和数据结构下隐藏了具体的实现细节,所以在VFS 层和内核的其他部分看来,所有文件系统都是相同的。

3. 中断和系统调用

为了处理是处理硬件外设I/O,有了中断机制这个东西。

中断分外部中断(硬件中断)和内部中断(软件中断)。内部中断⼜称为异常(Exception),异常⼜分为故障(fault)和陷阱(trap)。中断(广义)会改变处理器执行指令的顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应。中断是异步的:由硬件随机产生,在程序执行的任何时候可能出现;异常是同步的:在(特殊的或出错的)指令执行时由CPU控制单元产生。

系统调用作为一种特殊的中断,就是利⽤陷阱(trap)这种软件中断⽅式主动从⽤户态进⼊内核态的。

此时就不得不牵扯到操作系统的“两把宝剑”进程上下文和中断上下⽂。

进程上下文是把系统提供给进程的处于动态变化的运行环境总和。

中断上下文它是一个内核控制路径,代表了中断发生时正在运行的进程执行。

中断的处理过程:

确定中断向量。
利用中断向量在IDT中找到对应中断门,在中断门中得到段选择符从而可以从GDT中找到中断服务例程的段基址。
确定中断发生的特权级合法(linux只有内核态和用户态两种特权级,此步用来检查中断程序的特权是否低于引起中断的程序的特权,低优先级程序不能引起高优先级程序)
检查是否发生特权级变化(用户态陷入内核态,这时候需要设置内核的堆栈),如果发生读取当前程序的tss段(通过tr寄存器读取)来选择新特权级的ss和esp指针,然后保存旧的ss和esp指针。
若发生的是故障,用引起异常的指令地址修改cs和eip寄存器的值,以使得这条指令在异常处理结束后能被再次执行。
在栈中保存eflags、cs和eip的内容。
如果异常产生一个硬件出错码,则将它保存在栈中。
装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。这对寄存器值给出中断或者异常处理程序的第一条指定的逻辑地址。

系统调用的过程:

课程学习报告_第2张图片

  • 应用程序 代码调用系统调用( xyz ),该函数是一个包装系统调用的 库函数 ;
  • 库函数 ( xyz )负责准备向内核传递的参数,并触发 软中断 以切换到内核;
  • CPU 被 软中断 打断后,执行 中断处理函数 ,即 系统调用处理函数 ( system_call);
  • 系统调用处理函数 调用 系统调用服务例程 ( sys_xyz ),真正开始处理该系统调用

4. 总结

很惭愧,在疫情期间没有做到自觉得学习,有负孟老师和李老师的付出。实际学习中,对很多概念只能做到宏观上理解,很多问题都是不求甚解的状态,尤其涉及到内核C代码,很多没见过的语法和数据结构让我很迷糊。我个人使用linux系统已有6年多的时间,因为没有静心研究过内核,导致我对linux的认识只浮于表面。所幸今后的实习工作需要用到linux平台,也算是有了一个补充操作系统知识的契机。此后我将以博客的形式,对所学所记进行记录总结。

你可能感兴趣的:(课程学习报告)