信号安装

更新时间:
2024-03-14
下载文档

信号安装

本节介绍信号安装的方法。

函数 signal

SylixOS 信号机制中最简单的接口是 signal 函数:

#include <signal.h>
void  (*signal(int  iSigNo, void (*pfuncHandler)(int)))(int);

函数 signal 原型分析:

  • 此函数成功返回一个函数指针,失败返回 SIG_ERR,如下表所示。
    • 这个函数指针指向的函数没有返回值。
    • 参数是一个整型值。
  • 参数 iSigNo 是下表中的任一信号名。
  • 参数 pfuncHandler 是要安装的信号函数或常量 SIG_IGN、常量 SIG_DFL。

我们查看 <system/signal/signal.h> 会发现如下表形式的定义:

宏名
SIG_ERR(PSIGNAL_HANDLE)-1
SIG_DFL(PSIGNAL_HANDLE)0
SIG_IGN(PSIGNAL_HANDLE)1
SIG_CATCH(PSIGNAL_HANDLE)2
SIG_HOLD(PSIGNAL_HANDLE)3

注意:
宏 PSIGNAL_HANDLE 可在 <kernel/include/k_ptype.h> 中发现:

typedef  VOID  (*PSIGNAL_HANDLE)(INT);

在之前的 UNIX 系统实现中,signal 函数安装的信号是不可靠的,因为安装的信号不是永久的,只要信号被递送,则信号动作将恢复成默认动作。值得庆幸的是,SylixOS 的信号机制支持 POSIX 实时扩展部分,保证了 signal 函数将永久安装一个信号。

函数 sigaction

sigaction 函数检查或修改与指定信号相关联的处理动作。此函数取代了 signal 函数,在 SylixOS 中 signal 函数通过调用 sigaction 函数实现。

#include <signal.h>
int  sigaction(int                      iSigNo, 
               const struct sigaction  *psigactionNew,
               struct sigaction        *psigactionOld);

函数 sigaction 原型分析:

  • 此函数成功时返回 0,失败时返回 -1 并设置错误号。
  • 参数 iSigNo 是下表中的任一信号名。
  • 参数 psigactionNew 是新的信号处理结构。
  • 输出参数 psigactionOld 保存之前的处理结构。
信号名说明
SIGHUP挂断控制终端或进程。通常用此通知守护进程再次读取它们的配置文件,因为守护进程不会有控制终端,通常决不会接收到这种信号
SIGINT来自键盘的中断。一般采用 Ctrl + C 来产生此信号。当一个进程在运行时失控,特别是他正在屏幕上产生大量不需要的输出时,常用此信号终止
SIGQUIT来自键盘的退出
SIGILL非法指令
SIGTRAP跟踪断点
SIGABRT异常结束
SIGUNUSED未使用
SIGFPE协处理出错,如除以 0、浮点溢出等
SIGKILL强迫进程结束(不能被忽略或捕捉)
SIGBUS总线错误,通常是指示一个实现定义的硬件故障
SIGSEGV无效内存引用
SIGUNUSED2未使用 2
SIGPIPE管道写错误,无读者
SIGALRM实时定时器报警
SIGTERM进程终止。这是 kill 命令的默认动作,由于这个信号是由应用程序捕获的,使用 SIGTERM 也让程序有机会在退出之前做好清理工作,从而优雅的终止
SIGCNCL线程取消
SIGSTOP停止进程执行。此信号不能被捕获和忽略(不能被忽略或捕捉)
SIGTSTPtty 发出停止进程
SIGCONT恢复进程继续执行
SIGCHLD子进程停止或者被终止。系统默认是忽略此信号
SIGTTIN后台进程请求输入
SIGTTOU后台进程请求输出
SIGCANCEL同 SIGTERM 相同
SIGIO异步 I/O 事件
SIGXCPU进程超出了软 CPU 事件限制
SIGXFSZ进程超出了软文件长度限制
SIGVTALRM函数 setitimer 设置的虚拟间隔定时器已经超时
SIGPROF函数 setitimer 设置的梗概间隔定时器已经超时
SIGWINCH更改了窗口的大小
SIGINFO信息请求
SIGPOLL同 SIGIO 相同
SIGUSR1用户定义信号 1
SIGUSR2用户定义信号 2
SIGPWR电源失败重新开始
SIGSYS错误的系统调用
SIGURG网络连接上接到带外的数据时,可选择地产生此信号
SIGRTMIN-SIGRTMAXSylixOS 实现 SIGRTMIN = 48、SIGRTMAX = 63,系统没有指定明确的含义,由用户自定义,并且不应该使用某数值

sigaction 函数使用下面的结构来检查或修改指定信号相关联的处理动作:

struct sigaction {
    union {
        PSIGNAL_HANDLE        _sa_handler;
        PSIGNAL_HANDLE_ACT    _sa_sigaction;
    } _u;                                  /*  信号服务函数句柄         */
    sigset_t                  sa_mask;     /*  执行时的信号屏蔽码       */
    INT                       sa_flags;    /*  该句柄处理标志           */
    PSIGNAL_HANDLE            sa_restorer; /*  恢复处理函数指针         */
};
#define sa_handler      _u._sa_handler
#define sa_sigaction    _u._sa_sigaction

当更改信号动作时,如果 sa_handler 成员包含一个信号捕捉函数的地址(不是常量 SIG_IGN 或 SIG_DFL),则 sa_mask 成员包含了一个信号集,在调用该信号捕捉函数之前,这一信号集要加到线程的信号屏蔽字中。sa_flags 成员指定对信号进行处理的各个选项。如下表所示 sa_flags 成员标志的意义。

选项说明
SA_NOCLDSTOP子进程被删除时不要产生信号
SA_NOCLDWAIT不产生僵尸进程
SA_SIGINFO信号句柄需要 siginfo 参数
SA_ONSTACK自定义栈
SA_RESTART执行信号句柄后重启调用
SA_INTERRUPT执行信号句柄后不重启调用
SA_NOMASK不阻止在指定信号处理句柄中再收到信号
SA_RESETHAND执行句柄后,将信号句柄设置为默认动作

如果 sa_flags 包含 SA_NOCLDSTOP 标志,父进程不接收子进程的暂停信号,SIGCHLD 信号被忽略,SIGCHLD 信号在“进程与信号”做详细介绍。

指定 SA_NOCLDWAIT 标志,将由系统接管回收子进程的资源,因此不会产生僵尸进程。

指定 SA_NOMASK 标志,在执行信号处理函数时,如果收到相同信号则会被中断,如此将会形成递归。

指定 SA_RESETHAND 标志,执行一次信号处理函数后,信号动作将设置为默认动作,此标志兼容了之前不可靠的信号机制。

sa_sigaction 成员是一个替代的信号处理程序,在 sigaction 结构中如果使用了 SA_SIGINFO 标志,则使用该信号处理程序。在 SylixOS 中,sa_sigaction 成员和 sa_handler 成员使用了同一存储区,所有应用程序只能一次使用这两个成员中的一个。

通常,如果使用 sa_handler 成员,按下面方式调用信号处理程序:

void handler(int signo);
  • 如果使用 sa_sigaction 成员,也就是设置了 SA_SIGINFO 标志,那么按下面方式调用信号处理程序:
void handler(int signo, siginfo_t *siginfo, void *arg);
  • siginfo_t 结构包含了信号产生原因的有关信息,在 SylixOS 中该结构如下定义:
typedef struct siginfo {
    INT    si_signo;
    INT    si_errno;
    INT    si_code;
    union {
        struct {
            INT                _si_pid;
            INT                _si_uid;
        } _kill;
        struct {
            INT                _si_tid;
            INT                _si_overrun;
        } _timer;
        struct {
            INT                _si_pid;
            INT                _si_uid;
        } _rt;
        struct {
            INT                _si_pid;
            INT                _si_uid;
            INT                _si_status;
            clock_t            _si_utime;
            clock_t            _si_stime;
        } _sigchld;
        struct {
            INT                _si_band;
            INT                _si_fd;
        } _sigpoll;
    } _sifields;
#define si_pid                _sifields._kill._si_pid
#define si_uid                _sifields._kill._si_uid
#define si_timerid            _sifields._timer._si_tid
#define si_overrun            _sifields._timer._si_overrun
#define si_status             _sifields._sigchld._si_status
#define si_utime              _sifields._sigchld._si_utime
#define si_stime              _sifields._sigchld._si_stime
#define si_band               _sifields._sigpoll._si_band
#define si_fd                 _sifields._sigpoll._si_fd
    union sigval              si_value;
#define si_addr               si_value.sival_ptr /*  Faulting insn/memory ref  */
#define si_int                si_value.sival_int
#define si_ptr                si_value.sival_ptr
    ……
} siginfo_t;

union sigval 将在“队列信号”小节做详细介绍,成员 si_code 指示了信号的产生原因,如下表所示 SylixOS 中各种信号的 si_code 值定义。信号处理函数的第三个参数在 SylixOS 中返回栈的地址或者 NULL。

sa_restorer 成员是被废弃的,不应该被使用。

信号代码说明
ANYSI_KILL
SI_USER
SI_QUEUE
SI_TIMER
SI_ASYNCIO
SI_MESGQ
SI_KERNEL
使用 kill()发送的信号
同 SI_KILL
使用 sigqueue 发送的信号
POSIX 定时器发送的信号
异步 I/O 系统完成发送的信号
接收到一条消息产生的信号
SylixOS 内核内部使用
SIGILLILL_ILLOPC
ILL_ILLOPN
ILL_ILLADR
ILL_ILLTRP
ILL_PRVOPC
ILL_PRVREG
ILL_COPROC
ILL_BADSTK
非法操作码
非法操作数
非法地址模式
非法陷入
特权操作码
特权寄存器
协处理器出错
内部栈出错
SIGFPEFPE_INTDIV
FPE_INTOVF
FPE_FLTDIV
FPE_FLTOVF
FPE_FLTUND
FPE_FLTRES
FPE_FLTINV
FPE_FLTSUB
整数除以 0
整数溢出
浮点除以 0
浮点向上溢出
浮点向下溢出
浮点不精确结果
无效浮点操作
下标超出范围
SIGSEGVSEGV_MAPERR
SEGV_ACCERR
地址不映射至对象
对于映射对象的无效权限
SIGBUSBUS_ADRALN
BUS_ADRERR
BUS_OBJERR
无效地址对齐
不存在的物理地址
对象特定硬件错误
SIGTRAPTRAP_BRKPT
TRAP_TRACE
进程断点陷入
进程跟踪陷入
SIGCHLDCLD_EXITED
CLD_KILLED
CLD_DUMPED
CLD_TRAPPED
CLD_STOPPED
CLD_CONTINUED
子进程终止
子进程已异常终止(无 core)
子进程已异常终止(有 core,目前 SylixOS 不支持 core 文件)
被跟踪子进程已陷入
子进程已停止
停止的子进程已继续
SIGPOLLPOLL_IN
POLL_OUT
POLL_MSG
POLL_ERR
POLL_PRI
POLL_HUP
数据输入可用
输出缓冲区可用
输入消息可用
I/O 错误
高优先级输入可用
设备断开

下面实例展示了 sigaction 函数的使用方法,程序中 alarm 函数会在之后小节做详细介绍。

#include <stdio.h>
#include <signal.h>
void handler (int  signum, siginfo_t *siginfo, void *arg)
{
    fprintf(stdout, "alarm signal.\n");
}
int main (int argc, char *argv[])
{
    struct sigaction newact, oldact;
    int              ret;

    newact.sa_sigaction         = handler;
    newact.sa_flags             = SA_SIGINFO;

    sigemptyset(&newact.sa_mask);
    ret = sigaction(SIGALRM, &newact, &oldact);
    if (ret < 0) {
        fprintf(stderr, "sigaction error.\n");
        return  (-1);
    }
    alarm(2);
    sleep(5);
    sigaction(SIGALRM, &oldact, NULL); /*  恢复之前的信号行为       */
    return  (0);
}

在 SylixOS Shell 下运行程序,结果如下:

# ./Sigaction
Alarm signal.
文档内容是否对您有所帮助?
有帮助
没帮助