一、linux模型
Linux系统一般有4个主要部分
内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。
1.linux内核
内核(Kernal)是整个操作系统的核心,管理着整个计算机的软硬件资源。内核控制整个计算机的运行,提供相应的硬件驱动程序、网络接口程序,并管理所有程序的执行。内核提供的都是操作系统最基本的功能。
linux内核源代码主要是用C语言编写的,linux内核采用比较模块化的结构,主要模块包括存储管理、进程管理、文件系统管理、设备管理和驱动、网络通信和系统调用等。
2.linux shell
shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。实际上,shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。shell还有自己的编程语言用于命令编辑,它允许用户编写由shell命令组成的程序。shell编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的shell程序与其他应用程序具有同样的效果。
3.linux文件结构
文件结构是文件存放在磁盘等存储设备上的组织方法,主要体现在对文件和目录的组织上。目录提供了管理文件的一个方便而有效的途径。我们能够从一个目录切换到另一个目录,而且可以设置目录和文件的权限,设置文件的共享程度。
4.linux应用程序
标准的Linux系统一般都有一套都有称为应用程序的程序集,它包括文本编辑器、编程语言、XWindow、办公套件、Internet工具和数据库等。
二、系统调用
1.系统调用
Linux内核中设置了一组bai用于实现各种系统功能的子程序,称为du系zhi统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看,系统调用和普通的函数调用非常相似。区别仅仅在于,系统调用由操作系统核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。
2.系统调用的意义
系统调⽤的意义是操作系统为⽤户态进程与硬件设备进⾏交互提供了⼀组接⼝。系统调⽤具有以下功能和特性。
• 把⽤户从底层的硬件编程中解放出来。操作系统为我们管理硬件,⽤户态进程不⽤直接与硬件设备打交道。
• 极⼤地提⾼系统的安全性。如果⽤户态进程直接与硬件设备打交道,会产⽣安全隐患,可能引起系统崩溃。
• 使⽤户程序具有可移植性。⽤户程序与具体的硬件已经解耦合并⽤接⼝代替了,不会有紧密的关系,便于在不同系统间移植。
3.系统调用流程
系统调⽤的库函数就是我们使⽤的操作系统提供的 API(应⽤程序编程接⼝), API 只是函数定义。系统调⽤是通过特定的软件中断(陷阱 trap)向内核发出服务请求, int $0x80和syscall指令的执⾏就会触发⼀个系统调⽤。
当⽤户态进程调⽤⼀个系统调⽤时, CPU切换到内核态并开始执⾏system_call(entry_INT80_32或entry_SYSCALL_64)汇编代码,其中根据系统调⽤号调⽤对应的内核处理函数。
参考上图,执行流程实例如下:
1. 应用程序代码调用 xyz(),该函数是一个包装系统调用的库函数;
2. 库函数 xyz() 负责准备向内核传递的参数,并触发软中断以切换到内核;
3. CPU 被软中断打断后,执行中断处理函数,即系统调用处理函数(system_call);
4. 系统调用处理函数调用系统调用服务例程(sys_xyz ),真正开始处理该系统调用。
三、进程管理
Linux是一个多任务多用户操作系统,一个任务(task)就是一个进程(process)。 每一个进程都具有一定的功能和权限, 它们都运行在各自独立的虚拟地址间。在Linux中,
进程是系统资源分配的基本单位, 也是使用CPU运行的基本调度单位。存放在磁盘上的可执行文件的代码和数据的集合称为可执行映象(Executable Image)。当一个可执行映像装入系统中运行时, 它就形成了一个进程 。
1.进程的状态
运行态: 进程正在使用CPU运行的状态。 处于运行态的进程又称为当前进程( current process) 。
可运行态: 进程已分配到除CPU外所需要的其它资源, 等待系统把CPU分配给它之后即可投入运行。
等待态: 又称睡眠态, 它是进程正在等待某个事件或某个资源时所处的状态。 等待态进一步分为可中断的等待态和不可中断的等待态。 处于可中断等待态的进程可以由信号(signal)解除其等待态。处于不可中断等待态的进程, 一般是直接或间接等待硬件条件。它只能用特定的方式来解除, 例如使用唤醒函数wake_up()等。
暂停态: 进程需要接受某种特殊处理而暂时停止运行所处的状态。通常进程在接受到外部进程的某个信号进入暂停态, 例如, 正在接受调试的进程就处于这种状态。
僵死态: 进程的运行已经结束, 但它的任务结构体仍在系统中。
2.进程切换
为了控制进程的执行, 内核必须有能力挂起正在CPU上执行的进程, 并恢复以前挂起的某个进程的执行,这叫做进程切换( process switch)。
本质上说进程切换由两步组成:
- 切换页全局目录以安装一个新的地址空间;
- 切换内核态堆栈和硬件上下文
3.硬件上下文切换
硬件上下文: 进程恢复执行前必须装入寄存器的一组数据包括通用寄存器的值以及一些系统寄存器
switch_to宏执行进程切换, schedule()函数调用这个宏一调度一个新的进程在CPU上运行
switch_to利用了prev、 next和last三个参数:
- prev: 指向当前进程
- next: 指向被调度的进程
- last:输出参数, 表示被切换进程的描述符在内存中的位置
这个宏和函数的被调用关系:
schedule() --> context_switch() --> switch_to --> __switch_to()
当schedule()需要暂停A进程的执行而继续B进程的执行时, 就发生了进程之间的切换。 进程切换主要有两部分:
- 切换全局页表项;
- 切换内核堆栈和硬件上下文。
切换全局页表项这个切换工作由context_switch()完成。 其中switch_to和__switch_to()要完成第二部分。
四、课程心得
通过linux操作系统分析课程,让我对linux操作系统有了初步的认识,理解了linux的系统调用,进程管理以及文件系统的管理。尤其这次学习,通过汇编语言来解释堆栈切换,让我对进程切换中堆栈的切换有了更深的理解。这次网课虽然没有线下课质量高,但是两位老师都还是非常关心我们有没有听懂,并耐心解释,非常有责任心。非常感谢孟宁老师和李春杰老师的悉心教导。