20145318 《信息安全系统设计基础》第11周学习总结

20145318 《信息安全系统设计基础》第11周学习总结

教材学习内容总结

异常

  • 异常是异常控制流的一种形式,它一部分是由硬件实现的,一部分是有操作系统实现的。

  • 异常:控制流中的突变,用来响应处理器状态中的某些变化。

  • 在处理器中,状态被编码为不同的位和信号。状态变化成为事件。

  • 异常表:当处理器监测到有时间发生时,通过一张叫做异常表的跳转表,进行一个间接过程调用,到一个专门设计用来处理这类事件的操作系统子程序(异常处理程序)。

  • 当异常处理程序完成处理后,根据引起异常的事件的类型,会发生以下三种情况的一种:

    • 处理程序将控制返回给当前指令Icurr,即当事件发生时正在执行的指令。

    • 处理程序将控制返回给Inext,即如果没有发生异常将会执行的下一条指令。

    • 处理程序终止被中断的程序。

  • 异常号:到异常表中的索引

  • 异常表基址寄存器:异常表的起始地址存放的位置。

  • 异常与过程调用的异同:

    • 过程调用时,在跳转到处理器之前,处理器将返回地址压入栈中。然而,根据异常的类型,返回地址要么是当前指令,要么是下一条指令。

    • 处理器把一些额外的处理器状态压入栈里,在处理程序返回时,重新开始被中断的程序会需要这些状态。

    • 如果控制从一个用户程序转移到内核,那么所有这些项目都被压到内核栈中,而不是压到用户栈中。
      异常处理程序运行在内核模式下,意味着它们对所有的系统资源都有完全的访问权限。

异常的类别

  • 异常的分类:中断、陷阱、故障和终止。

  • 中断:异步发生,是来自处理器外部的I/O设备的信号的结果。 硬件异常中断处理程序通常称为中断处理程序。

  • 陷阱和系统调用:

    • 陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,叫做系统调用。

    • 普通的函数运行在用户模式中,用户模式限制了函数可以执行的指令的类型,而且它们只能访问与调用函数相同的栈。系统调用运行在内核模式中,内核模式允许系统调用执行指令,并访问定义在内核中的栈。

  • 故障:是由错误情况引起的。

  • 终止:是不可恢复的致命错误造成的结果,通常是一些硬件错误。终止处理程序从不将控制返回给应用程序。

  • 031号:由intel架构师定义的异常;32255号:操作系统定义的中断和陷阱。

  • 每一个系统调用都有一个唯一的整数号,对应于一个到内核中跳转表的偏移量。

进程

  • 进程,就是一个执行中的程序的实例,系统中的每个程序都是定义在运行在某个进程的上下文中的。异常是允许操作系统提供进程的概念所需要的基的本构造块。

  • 进程提供给应用程序的关键抽象:

    • 一个独立的逻辑控制流,独占地使用处理器;

    • 一个私有的地址空间,独占地使用存储器系统。

逻辑控制流

  • PC的值唯一地对应于包含在程序可执行目标文件中的指令,或者是包含在运行时动态链接到程序的共享对象中的指令。这个PC值的序列叫做逻辑控制流。

  • 进程轮流使用处理器,每个进程执行流的一部分,然后被抢占(暂时挂起)。

并发流

  • 并发流:一个逻辑流的执行在时间上与另一个流重叠。

    • 并发:多个流并发地执行的一般现象。

    • 多任务:一个进程和其他进程轮流运行的概念。

    • 时间片:一个进程执行它的控制流的一部分的每一时间段。

    • 多任务也叫时间分片。

  • 并行流:如果两个流并发的运行在不同的处理器核或者计算机上。

私有地址空间

  • 一个进程为每个程序提供他自己的私有地址空间,一般而言,和这个空间中某个地址相关联的存储器字节不能被其他程序读或写。

  • 地址空间底部是保留给用户程序的,顶部保留给保留给内核,用来存放内核在代表进程执行时的指令。

用户模式和内核模式

  • 模式位:用某个控制寄存器中的一个位模式,限制一个应用可以执行的指令以及它可以访问的地址空间范围。

  • 当设置了位模式,进程就运行在内核模式中,一个运行在内核模式中的进程可以中兴指令集中的任何指令,而且可以访问系统中任何存储器位置。

  • 没有设置位模式时,进程就运行在用户模式中,不允许执行特权指令,例如停止处理器、改变位模式,或者发起一个I/O操作。

  • 用户程序必须通过系统调用接口间接的当问内核代码和数据。
    进程从用户模式变为内核模式的唯一方法是通过诸如中断、故障、或者陷入系统调用这样的异常。

上下文切换

  • 上下文就是内核重新启动一个被抢占的进程所需的状态。

  • 调度:内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程。有内核中称为调度器的代码处理的。

  • 上下文切换机制:

    • 保存当前进程的上下文

    • 恢复某个先前被抢占的进程被保存的上下文

    • 将控制传递给这个新恢复的进程

  • 引起上下文切换的情况

    • 当内核代表用户执行系统调用时

    • 中断时

系统调用错误处理

  • Unix系统级函数遇到错误时,会典型地返回-1,并设置全局变量errno来表示出错内容。

  • 通过使用错误处理包装函数,可以进一步简化代码。

进程控制

获取进程ID

  • 每个进程都有一个唯一的正数的进程ID。

  • getpid函数返回调用进程的PID,getppid函数返回它的父进程的PID。上面两个函数返回一个同类型为pid_t的整数值,在linux系统中,它在types.h中被定义为int。

创建和终止进程

  • 进程总处于三种状态

    • 运行:进程要么在CPU上执行,要么在等待被执行且最终会被内核调度。

    • 停止:程序的执行被挂起,,且不会被调度。

    • 终止:进程用永远停止了。终止原因:(1)收到一个信号,默认行为是终止进程;(2)从主进程返回(3)调用exit函数。

  • 父进程通过调用fork函数创建一个新的运行的子进程。

  • 子进程和父进程的异同:

    • 异:有不同的PID

    • 同:用户级虚拟地址空间,包括:文本、数据和bss段、堆以及用户栈。任何打开文件描述符,子进程可以读写父进程中打开的任何文件。

  • fork函数: 因为父进程的PID总是非零的,返回值就提供一个明确的方法来分辨程序是在父进程还是在子进程中执行。

  • fork函数的特点:

    • 调用一次,返回两次

    • 并发执行

    • 相同的但是独立的地址空间

共享文件

  • 回收子进程

  • 当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程。

  • 一个终止了但还未被回收的进程称为僵死进程。

  • 一个进程可以通过调用waitpid函数来等待它的子进程终止或者停止。

      #include <sys/types.h>
      #include <sys/wait.h>
    
      pid_t waitpid(pid_t pid,int *status,int options);
      //返回:若成功,返回子进程的PID;若WNOHANG,返回0;若其他错误,返回-1
    
  • 修改默认行为,通过options设置:

    • WNOHANG:默认行为是挂起调用进程。

    • WUNTRACED:默认行为是只返回已终止的子进程。

    • WNOHANG|WUNTRACED:立即返回,如果等待集合中没有任何子进程被停止或者已终止,那么返回值为0,或者返回值等于那个被停止或者已经终止的子进程的PID。

  • 错误条件:

    • 若调用进程没有子进程,那么waitpid返回-1,并且设置errno为ECHILD;

    • 若waitpid函数被一个信号中断,那么返回-1,并设置errno为EINTR

信号

信号术语

  • 发送信号的两个不同步骤:

    • 发送信号:内核通过更新目的进程上下文中的某个状态,发送(递送)一个信号给目的进程。

    • 接收信号:信号处理程序捕获信号的基本思想。

  • 发送信号的两个原因:

    • 内核监测到一个系统事件,比如被零除错误或者子进程终止。

    • 一个进程调用了kill函数,显式地要求内核发送一个信号给目的进程。一个进程可以发送信号给它自己。

  • 待处理信号:一个只发出而没有被接收的信号

  • 一个进程可以有选择性地阻塞接收某种信号。

  • 待处理信号不会被接收,直到进程取消对这种信号的阻塞。

  • 一个待处理信号最多只能被接受一次,pending位向量:维护着待处理信号集合,blocked向量:维护着被阻塞的信号集合。

发送信号

  • 进程组:每个进程都只属于一个进程组,进程组是由一个正整数进程组ID来标识的。getpgrp函数返回当前进程的进程组ID:默认地,一个子进程和它的父进程同属于一个进程组。

  • 用/bin/kill/程序发送信号:一个为负的PID会导致信号被发送到进程组PID中的每个进程。

  • 从键盘发送信号:作业:表示对一个命令行求值而创建的进程。外壳为每个作业创建一个独立的进程组。

  • 用kill函数发送信号: 进程通过调用kill函数发送信号给其他的进程。父进程用kill函数发送SIGKILL信号给它的子进程。

  • 用alarm函数发送信号:在任何情况下,对alarm的调用都将取消任何待处理的闹钟,并且返回任何待处理的闹钟在被发送前还剩下的秒数。

接收信号

  • 当内核从一个异常处理程序返回,准备将控制传递该进程p时,它会检查进程p的未被阻塞的待处理信号的集合。如果这个集合是非空的,那么内核选择集合中的某个信号k,并且强制p接收信号k。

  • 进程可以通过使用signal函数修改和信号相关联的默认行为。 唯一例外是SIGSTOP和SIGKILL,它们的默认行为是不能被修改的。

      #include <signal.h>
      typedef void (*sighandler_t)(int);
    
      sighandler_t signal(int signum,sighandler_t handler);
      //返回:若成功,返回指向前次处理程序的指针;若出错,为SIG_ERR
    
  • signal函数改变和信号signum相关联的行为的三种方法:

    • handler是SIG_ IGN,忽略类型为signum的信号;

    • handler是SIG_ DFL,类型为signum的信号行为恢复为默认行为。

    • 否则,handler就是用户定义的函数地址。这个函数称为信号处理程序。

  • 设置信号处理程序:通过把处理程序的地址传递到signal函数从而改变默认行为。

    • 捕获信号:调用信号处理程序。

    • 处理信号:执行信号处理程序。

  • 因为信号处理程序的逻辑控制流与主函数的逻辑控制流重叠,信号处理程序和主函数并发执行。

信号处理问题

  • 待处理信号被阻塞:

  • 待处理信号不会排队等待;

  • 系统调用可以被中断:像read、wait、accept这样的系统调用潜在地会阻塞进程一段较长的时间,称为慢速系统调用。

  • 注意:不可以用信号来对其他进程中发生的事件计数。

实践截图












本周代码托管截图

学习进度条

参考资料

原文地址:https://www.cnblogs.com/zy1111/p/6107991.html