• 20191323王予涵第六章学习笔记


    20191323王予涵第六章学习笔记

    信号和信号处理

    一、知识点归纳

    信号和信号中断

    中断:发送给"进程"的事件,它将"进程"从正常活动转移到其他活动

    中断的种类:

    • 硬件中断
    • 其他进程的中断
    • 自身造成的中断

    其中,每个中断都有唯一的向量号,动作函数是中断表中的中断处理程序。

    Unix/Linux中的信号处理

    信号类型

    Unix/Linux支持的31种信号,在signal.h文件中均有定义

    #define  	SIGHUP  	1
    #define  	SIGINT  	2
    #define  	SIGQUIT  	3
    #define  	SIGILL  	4
    #define  	SIGTRAP  	5
    #define  	SIGABRT  	6
    #define  	SIGIOT  	6
    #define  	SIGBUS  	7
    #define  	SIGFPE  	8
    #define  	SIGKILL  	9
    #define  	SIGUSR1  	10
    #define  	SIGSEGV  	11
    #define  	SIGUSR2  	12
    #define  	SIGPIPE  	13
    #define  	SIGALRM  	14
    #define  	SIGTERM	        15
    #define  	SIGSTKFLT	16
    #define  	SIGCHLD    	17
    #define  	SIGCONT	        18
    #define  	SIGSTOP      	19
    #define  	SIGTSTP	        20
    #dpfine  	STGTTTN	        21
    #define  	SIGTTOU	        22
    #define  	SIGURG	        23
    #define  	SIGXCPU	        24
    #define  	SIGXFSZ    	25
    #define  	SIGVTALRM	26
    #define  	SIGPROF  	27
    #define  	SIGWINCH	28
    #define  	SIGPOLL  	29
    #define  	SIGPWR	        30
    #define  	SIGSYS	        31
    

    信号处理数组

    signal bits:

    0 = no signal

    1= signal

    31 30 ··· I ··· 1 0
    ··· 1 ···

    若向量位中I为1,则会产生信号I,并发送给相应进程

    signal mask:

    0 = no block

    1 = block

    ··· 0 ···

    若屏蔽位I为1,则信号会被阻塞或屏蔽

    signal handler:

    0 = default

    1 = ignore

    other = catcher address

    ··· 0 ···

    若发现为阻塞信号时,则将信号位清除为0,并尝试通过信号处理数组中的处理函数来处理该信号

    信号捕捉函数

    #include <signal.h> 
    int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
    
     struct sigaction {
              void (*sa_handler)(int);
         	  void (*sa_sigaction)(int sig, siginfo_t *siginfo, void *context)
              sigset_t sa_mask;
              int sa_flags;
         	  void (*sa_restorer)(void);
               };
    
    • sa_handler:指向默认处理函数的指针
    • sa_sigaction:用户定义的处理函数
    • sa_mask:执行期间需要阻塞的信号
    • sa_flags:修改信号处理进程的行为,若要使用sa_sigaction函数,必须将sa_flags设置为SA_SIGINFO

    信号处理步骤

    1. 当某进程处于内核模式时,会检查信号并处理未完成的信号。如果某信号有用户安装的捕捉函数,该进程会先清除信号,获取捕捉函数地址,对于大多数陷阱信号,则将已安装的捕捉函数重置为DEFault。然后,它会在用户模式下返回,以执行捕捉函数,以这种方式篡改返回路径。当捕捉函数结束时,它会返回到最初的中断点,即它最后进入内核模式的地方。因此,该进程会先迁回执行捕捉函数,然后再恢复正常执行。
    2. 重置用户安装的信号捕捉函数:用户安装的陷阱相关信号捕捉函数用于处理用户代码中的陷阱错误。由于捕捉函数也在用户模式下执行,因此可能会再次出现同样的错误。如果是这样,该进程最终会陷入无限循环,一直在用户模式和内核模式之间跳跃。为了防止这种情况,Unix内核通常会在允许进程执行捕捉函数之前先将处理函数重置为 DEFault。这意味着用户安装的捕捉函数只对首次出现的信号有效。若要捕捉再次出现的同一信号,则必须重新安装捕捉函数。但是,用户安装的信号捕捉函数的处理方法并不都一样,在不同Unix版本中会有所不同。例如,在 BSD Unix中,信号处理函数不会被重置,但是该信号在执行信号捕捉函数时会被阻塞。
    3. 信号号和唤醒:在Unix/Lintx内核中有两种SLEEP进程;深度休眠进程和浅度休眠进程。前一种进程不可中断,而后一种进程可由信号中断。如果某进程处于不可中断的SLEEP状态,到达的信号(必须来自硬件中断或其他进程)不会唤醒进程。如果它处于可中断的SLEEP状态,到达的信号将会唤醒它。例如,当某进程等待终端输入时,它会以低优先级休眠,这种休眠是可中断的,SIGINT这类信号即可唤醒它。

    信号用作IPC

    缺点:

    ● 每个信号由位向量中的一个位表示,只能记录一个信号的一次出现。如果某个进程向另一个进程发送两个或多个相同的信号,它们可能只在接收PROC中出现一次。

    ● 在执行信号捕捉函数时,虽然可以通过阻塞同一信号来防止竞态条件,但是无法防止丢失信号。

    ● 大多数信号都有预定义的含义。不加区别地任意使用信号不仅不能达到通信的目的,反而会造成混乱。

    二、实践捕捉除0异常信号

    "head.h"

    #ifndef HEAD_H_INCLUDED
    #define HEAD_H_INCLUDED
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <setjmp.h>
    jmp_buf env;
    int count = 0;
    #endif // HEAD_H_INCLUDED
    

    mian.c

    #include "head.h"
    void handler(int sig, siginfo_t *siginfo, void *context)
    {
        printf("handler: sig=%d from PID=%d UID=%d count=%d
    ", sig, siginfo -> si_pid,siginfo -> si_uid,++count);
        if(count >= 4)
        {
            longjmp(env,20191323);
        }
    }
    
    int BAD()
    {
        int i = 3;
        printf("in BAD(): try to divide zero
    ");
        i /= 0;
        printf("could not see this line");
    }
    int main(void)
    {
        int  r;
        struct sigaction act;
        memset(&act, 0, sizeof(act));
        act.sa_sigaction = &handler;
        act.sa_flags = SA_SIGINFO;
        sigaction(SIGFPE, &act,NULL);
        if((r = setjmp(env)) == 0)
        {
            BAD();
        }
        else
        {
            printf("proc %d survived SEGMENTATION FAULT : r = %d
    ", getpid(),r);
        }
        printf("proc %d looping
    ",getpid());
        while(1);
    
    }
    

    运行结果截图:

  • 相关阅读:
    线程池进程池
    设计原则与设计模式
    腾讯阿里第三方接入
    计划任务
    系统服务
    Python Faker模块
    Python openpyxl模块
    Python-docx模块
    进程管理
    磁盘管理
  • 原文地址:https://www.cnblogs.com/WANGYUHAN/p/15552705.html
Copyright © 2020-2023  润新知