BryanMelody

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

谈谈您对课程的心得体会,改进建议等。

进程管理

相关概念

  1. 进程和父进程:每个进程都有父进程,而所有的进程以init进程为根,形成一个树状结构

  2. 进程组:每个进程都会属于一个进程组(process group),每个进程组中可以包含多个进程。进程组会有一个进程组领导进程 (process group leader),领导进程的PID成为进程组的ID (process group ID, PGID),以识别进程组。

    kill给组发送信号进程组号前加负号如:kill -9 -2189

  3. 会话:一个或是多个进程组集合。 进程可以通过调用 pid_t setsid(); 来建立一个新会话,如果调用此函数的进程不是进程组长,就会创建一个新的会话,那么此时会:

    1. 该进程称为会话首进程 (session leader)
    2. 该进程称为进程组组长
    3. 该进程没有控制终端,即使之前有控制终端这种联系也会断掉

    可以使用第三个特性来创建 daemon 进程。 调用 getsid 可以获得会话首进程进程组 pid,也就是会话首进程进程 id。

  4. 控制终端:

    1. 一个会话持有一个控制终端 (controlling terminal),可以是终端设备也可以是伪终端
    2. 建立与控制终端连接的会话首进程被称为控制进程 (controlling process)
    3. 一个会话有多个进程组,允许存在多个后台进程组 (backgroup process group) 和一个前台进程组 (foregroup process group)
    4. 键入终端的中断键 (Ctrl+C) 会发送中断信号给前台进程组所有进程
    5. 键入终端的退出键 (Ctrl+) 会发送退出信号给前台进程组所有进程
    6. 终端或是网络断开会将挂断信号发送给会话首进程

进程状态

在Linux中,进程状态在task_stuct中定义及取值如下

volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */

#define TASK_RUNNING        0
#define TASK_INTERRUPTIBLE  1
#define TASK_UNINTERRUPTIBLE    2
#define __TASK_STOPPED      4
#define __TASK_TRACED       8
/* in tsk->exit_state */
#define EXIT_ZOMBIE     16
#define EXIT_DEAD       32
/* in tsk->state again */
#define TASK_DEAD       64
#define TASK_WAKEKILL       128
#define TASK_WAKING     256
#define TASK_STATE_MAX      512

  Linux进程间状态转换和内核调用图

 进程调度

内存中保存了对每个进程的唯一描述,,并通过若干结构与其他进程连接起来。调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分,,其中一个涉及调度策略, 另外一个涉及上下文切换。

中断机制

系统调用是一种特殊的中断

中断分外部中断(硬件中断)和内部中断(软件中断),内部中断⼜称为异常(Exception),异常⼜分为故障(fault)和陷阱(trap)。系统调⽤就是利⽤陷阱(trap)这种软件中断⽅式主动从⽤户态进⼊内核态的。⼀般来说,从⽤户态进⼊内核态是由中断触发的,可能是硬件中断,在⽤户态进程执⾏时,硬件中断信号到来,进⼊内核态,就会执⾏这个中断对应的中断服务例程。也可能是⽤户态程序执⾏过程中,调⽤了⼀个系统调⽤,陷⼊了内核态,叫作陷阱(trap)。所以,系统调⽤是特殊的中断。

系统调用和库函数API的区别:系统调用会进入内核态,而库函数则未必。

系统调用的传参方式

系统调⽤从⽤户态切换到内核态,在⽤户态和内核态这两种执⾏模式下使⽤的是不同的堆栈,即进程的⽤户态堆栈和进程的内核态堆栈,传递参数⽅法⽆法通过参数压栈的⽅式,⽽是通过寄存器传递参数的⽅式。寄存器传递参数的个数是有限制的,⽽且每个参数的⻓度不能超过寄存器的⻓度,32位x86体系结构下寄存器的⻓度最⼤32位。除了EAX⽤于传递系统调⽤号外,参数按顺序赋值给EBX、ECX、EDX、ESI、EDI、EBP(64位机为RDI、RSI、RDX、RCX、R8、R9这6个寄存器),参数的个数不能超过6个,即上述6个寄存器。如果超过6个就把某⼀个寄存器作为指针。

中断过程中中断上下文的切换过程(以系统调用为例)

int $0x80指令或syscall指令触发系统调⽤机制会在堆栈上保存⼀些寄存器的值,会保存中断发⽣时当前执⾏程序的栈顶地址(ESP、RSP)、当时的状态字(EFlags、RFlags)、当时的 CS:EIP/RIP 的值。同时会将当前进程内核态的栈顶地址、内核态的状态字放⼊ CPU 对应的寄存器,并且 CS:EIP/RIP 寄存器的值会指向中断处理程序的⼊⼝。中断保存了⽤户态 CS:EIP 的值,以及当前的堆栈段寄存器的栈顶,在 EFLAGS 寄存器的当前的值保存到内核堆栈⾥。然后执行SAVE_ALL ,完成中断服务,发⽣进程调度。如果没有发⽣进程调度,就直接 restore_all 恢复中断现场,然后 iret 返回到原来的状态。

总的来说,中断的全过程是当⼀个中断信号发⽣时,CPU把当前正在执⾏的进程X的CS:RIP寄存器和RSP寄存器等都压栈到了⼀个叫内核堆栈的地⽅,然后把CS:RIP指向⼀个中断处理程序的⼊⼝,做保存现场的⼯作,然后去执⾏其他进程⽐如Y,等重新回来时再恢复现场。

课程心得

这学期的课上的坎坎坷坷,因为疫情的原因只能通过网课的形式进行授课,虽然没有耽误课程的进度,但是网课的形式还是不如线下授课的效果理想,老师也没有办法有效的得到学生的反馈,学生存在疑问或问题的时候也不能很清晰的表达给老师。这是网课的弊端。

但网课的弊端是客观原因,并不代表二位老师的授课能力和水平不优秀。从这门课上,我们能了解到过去学过的操作系统的理论知识如何实际应用到Linux当中,加深理解、记忆。在课上孟老师能够用“庄周梦蝶”这样的比喻帮助学生理解课程内容,是十分形象、有效的,能够让晦涩的知识变得形象起来,希望能够发扬这一点,让原本晦涩难懂的知识变得生动、更加好理解一些。

课堂上的实验也受益不浅,增强自己的动手能力,从实践中学习。原本觉得Linux只是一个使用的工具,没有想到其中蕴含大量的知识,一时难以全部消化和理解,在以后的学习工作中会继续努力。

在此感谢孟宁老师和李春杰老师的认真授课,也感谢助教老师的付出。只是希望以后再也没有阻止我们正常上学上课的事了...

 

posted on 2020-07-09 19:14  BryanMelody  阅读(356)  评论(0)    收藏  举报