课程学习总结报告

Linux操作系统分析-课程学习总结报告

  • 作业要求
    根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。

一.Linux初始化

Linux系统模型要从开机开始讲起,当然前面的硬件相关的与这门课没有关系,这里从start_kernel开始。在start_kernel中,0号进程做了许多的事情,并对系统运行需要的诸多系统进行了初始化,这里只针对课上有涉及的部分以我的理解进行概述:

1.1 1号和2号进程

在Linux系统中,进程是进行资源分配和调度的最小单位,是整个操作系统的基础,而此时系统中只有0号进程init_task,要想要系统能够正常运行,需要更多的进程,且为了对内核资源进行保护,Linux分为了内核态和用户态,因此在start_kernel中0号进程在rest_init函数中采用fork生成1号进程kernel_init以及采用execv的方式生成2号进程Kthreadd,1号进程运行在用户态,用于创建用户进程,2号进程运行在内核态,用于创建内核进程。之后调用schedule函数开启了内核的调度系统,从此linux系统开始转起来了,最后rest_init最终调用cpu_idle函数结束了整个内核的启动。

1.2 中断相关初始化

中断是Linux系统中相当重要的一个部分,而中断的初始化就主要发生在start_kernel中。在start_kernel中系统分别采用trap_init 和 IRQ_init实现了对中断和异常的初始化,这两个函数通过调用set_trap_gate等多个函数把相应的门中的段 描述符设置成内核代码段的选 择符,偏移字段设置成addr。

1.3 时钟初始化

在操作系统中,时钟也是一个十分重要的概念,时钟可以确定当前进程的执行时间,考虑是否要抢占,检查到期的软定时器以赋予操作系统可以定时执行任务的功能.在start_kernel 中是用tick_init来实现时钟的初始化,时钟的初始化主要是两个部分,一个是从RTC中获取开机基准时间,因为RTC是独立在CPU之外的,即使关机也在运转,另一个就是在init_pit_timer初始化时钟源的频率,这个的目的是因为RTC不够准确,而通过例如TSC产生时钟频率可以修正RTC的精准度.

二.进程的运行

我们都知道进程是操作系统的基础,我们需要计算机做任何的事情都离不开进程的运行,那么一个进程如何才能在系统中运行起来,完成我们的需求呢?

2.1 进程的简介与进程的创建

Linux内核中的进程是⾮常复杂的,进程由程序、数据和进程控制块三部分组成在操作系统原理中,我们通过进程控制块PCB描述进程。为了管理进程,内核要描述进程的结构,我们也称其为进程描述符,进程描述符直接或间接提供了进程相关的所有信息。struct task_struct的数据结构⾮常庞⼤,其中state是进程状态,stack是堆栈等,从这个结构中struct task_struct的结构关系,⽐如进程的状态、进程双向链表的管理,以及控制台tty、⽂件系统fs的描述、进程打开⽂件的⽂件描述符fifiles、内存管理的描述mm,还有进程间通信的信号signal的描述等

整个的进程在操作系统中有点像树形的结构,除0号进程外,每个进程都有自己的父进程和兄弟进程。而这些进程都来源于0号进程,⽗进程通过fork系统调⽤进⼊内核_do_fork函数,复制进程描述符及相关进程资源(采⽤写时复制技术)、分配⼦进程的内核堆栈并对内核堆栈和thread等进程关键上下⽂进⾏初始化,最后将⼦进程放⼊就绪队列,fork系统调⽤返回,⽽⼦进程则在被调度执⾏时根据设置的内核堆栈和thread等进程关键上下⽂开始执行。

2.2 系统调用与中断

进程的创建需要系统调用,而系统调用其实就是特殊的中断,中断又分为硬件中断(中断)和软件中断(异常)。

当中断发生的时候,OS会首先确认与中断或异常关联的中断向量i, 然后去读取读idtr寄存器指向的IDT表中的第i项, 从gdtr寄存器获得GDT的基地址,并在GDT中查找, 以读取IDT表项中的段选择符所标识的段描述符,然后确认中断的源头,检查是否发生了特权变化,如果是从用户态陷入了内核态,需要开始使用新的内核态相关的堆栈,然后保存现场,在这之后异常和中断会有所区别:

异常是软件中断,通常通过函数就可以处理,因此此时OS会调用相关的C函数来处理异常相关的事务,最后通ret_from_exception()从异常处理程序退出。而中断通常需要和硬件设备打交道,因此在上述之后会为正在给IRQ线服务的PIC发送一个应答, 这将允许PIC进一步发出中断,硬件自动根据PIC或者APIC送出来的中断类型码(中断向量号)去查找中断描述符表的相应项,然后得到interrupt[n]的内容,然后调用do_IRQ来执行相关的处理,最后跳转到ret_from_intr退出。

2.3 进程与文件系统

在上一部分,我们知道进程由程序与数据和PCB组成,其中程序与数据本质上就是我们程序员写的代码以及提供的数据,这些也就是文件。文件系统也是操作系统的三大核心功能之一。同进程一样,文件控制块FCB是系统为管理文件而设置的一个数据结构。FCB是文件存在的标志,它记录了系统管理文件所需要的全部信息,包括文件名,文件物理地址,文件大小,文件创建时间等等信息。在Linux系统中一切有着有一切皆文件的思想,无论是正规文件,目录文件,符号链接,设备文件,管道文件, 套接字都通过VFS系统提供一个统一的接口。文件系统的一个最大特点是“按名存取”,用户只要给出文件的符号名就能方便地存取在外存空间的文件信息,而不必关心文件的具体物理地址。而文件系统最重要的三个功能就是open, read, 和write,而这三个中最重要的就是open,这里介绍一下open的过程:

第一部分:open会首先调用C库中的open函数,通过int 0x 80进行系统调用,然后获取中断异常向量表中获取128号中的段选择符和段内偏移(也即系统调用程序的入口地址),在系统调用中会进行保存现场,通过对指令分析获取用户提供的参数,然后获取系统调用表中对应的sys_open函数。第二部分:sys_open函数会进行命名查找,得到文件控制块,获取文件的类型,根据文件的类型调用不同的文件打开函数,文件打开函数会创建一个文件打开表(系统文件打开表),通过文件控制块填入相关信息,然后会返回进程中,进程中也会存在一个文件打开表,进程文件打开表就是进程的file中的fd数组,fd数组中存入指针会指向存入系统打开表中的表项,而那些表项对应着刚刚打开的文件,最后open会返回这个文件存在fd数组的下标。

有了上述的open过程,之后的read和write就会很简单了,read和write就可以根据上述的open返回的数组下标,找到对应的文件,然后就可以对文件进行读写。

另外,Linux中的设备,除网络设备外,字符设备和块设备都被映射到Linux文件系统的文件和目录,因此Linux中对设备的操作与上述讲的对普通文件的操作很类似,这里不再赘述。

2.4 进程的地址空间-内存分配

一个进程要运行,首先要经过文件系统讲进程相关的数据和程序加载到内存中,那么进程在内存中是如何分配的呢?

与进程地址空间有关的全部信息都包含在一个叫做内存描述符的数据结构中,Linux把进程地址空间分成内核区和用户区两部分,内核是操作系统中优先级最高的成分,因此内核中的函数以直接了当的方式获得动态内存。而给用户态进程分配内存的时候,请求被认为是不紧迫的,用户进程不可信任,因此,当用户态进程请求动态内存时,并没有立即获得实际的物理页框,而仅仅获得对一个新的线性地址区间的使用权,这个线性地址区间会成为进程地址空间的一部分,称作线性区。

2.5 进程切换

操作系统中存在这许多进程,而cpu是有限的,进程应该以什么方式来判断运行的优先级是操作系统的一个重要工作,进程调度的方式通常是基于优先级的调度,进程有两种队列分别是活动队列和过期队列,调度对象是活动队列,活动队列中优先级大的进程首先得到CPU投入运行,只有当活动队列都执行完了,过期队列的进程才会重新加入活动队列。如下图中,活动队列和过期队列中都有140个优先级,且都是通过链表进行连接。实时系统的优先级高于普通进程,普通进程又包含交互进程和批处理进程,为提高交互进程的性能,用完时间片的活动批处理 进程总是变成过期进程,用完时间片的活动交互进程通常仍然是活动进程,调度程序重填时间片把它留在活动进程集合中,如果最老的过期进程等待了很长时间,或者过期进程比交互进程的优先级高,调度程序把用完时间片的活动交互进程移到过期进程集合中。而实时进程总是被当做活动进程,调度程序总是让优先级高的进程运行。

三. 思考与建议

 谢谢孟老师和李老师的辛苦付出, 为我们带来这这么精品的课程。虽然是线上课程,但是实际体验比线下还要好。通过学习《Linux操作系统分析》,从对Linux操作系统的几乎一无所知,到学习了Linux操作系统从运行初始化到一个程序的真正运行过程,加深了对操作系统的了解。至于建议,希望李老师的那部分课程也可以安排一些实验或者实践相关的内容,可以加深理解。

posted @ 2020-07-09 09:14  白菜菜菜  阅读(202)  评论(0编辑  收藏  举报