《unix环境高级编程》信号——sigaction 函数

sigaction 函数

sigaction 函数的功能与 signal 类似,用于检查或修改与指定信号相关联的处理动作,一般在应用中使用 sigaction 函数。

/* sigaction函数 */
/*
 * 函数功能: 检查或修改与指定信号相关联的处理动作;此函数取代之前的signal函数;
 * 返回值:若成功则返回0,若出错则返回-1;
 * 函数原型:
 */
#include 
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
/*
 * 说明:
 * signo是要检查或修改其具体动作的信号编号;
 * 若act非空,则要修改其动作;
 * 若oact指针非空,则系统经由oact指针返回该信号上一个动作;
 *
 * struct sigaction 结构如下:
 */
struct sigaction
{
    void (* sa_handler)(int);   /* addr of signal handler, or SIG_IGN, or SIG_DFL */
    sigset_t sa_mask;           /* additional signals to block */
    int sa_flags;               /* signal options */

    /* alternate handler */
    void (*sa_sigaction)(int, siginfo_t *, void *);
};
/*
 * 说明:
 * 当更改动作时,若sa_handler 字段包含一个信号捕捉函数的地址,则sa_mask字段说明了一个信号集,在调用该信号捕捉函数之前,
 * 这一信号集要加到进程的信号屏蔽字中。仅当从信号捕获函数返回时再将进程的信号屏蔽字复位为原先值;
 * 其中sa_flags标志如下:
 * (1)SA_INTERRUPT    由此信号中断的系统调用不会自动重启;
 * (2)SA_NOCLDSTOP    若signo是SIGCHLD,当子进程停止时,不产生此信号,当子进程终止时,仍然产生此信号;若已设置此标志,则当停止的进程继续运行时,不发送SIGCHLD信号;
 * (3)SA_NOCLDWAIT    若signo是SIGCHLD,当子进程停止时,不创建僵死进程;若调用进程后面调用wait,则调用进程阻塞,直到其所有子进程都终止,此时返回-1,并将errno设置为ECHILD;
 * (4)SA_NOEFER       当捕捉到此信号时,在执行其信号捕捉函数时,系统不自动阻塞此信号;
 * (5)SA_NOSTACK      若用signaltstack(2)声明了一替换栈,则将此信号传递给替换栈上的进程;
 * (6)SA_RESETHAND    在此信号捕捉函数入口处,将此信号的处理方式复位为SIG_DEL,并清除SA_SIGINFO标志;
 * (7)SA_RESTART      由此信号中断的系统调用会自动重启动;
 * (8)SA_SIGINFO      此选项对信号处理程序提供附加信息:一个指向siginfo结构的指针以及一个指向进程上下文标识符的指针;
 */
sa_sigaction 字段是一个替代的信号处理程序,当在 sigaction 结构中使用了  SA_SIGINFO 标志时,使用该信号处理程序。通常,按下列方式调用信号处理程序:

void handler(int signo);
如果设置了 SA_SIGINFO 标志,那么按照下列方式调用信号处理程序:

void handler(int signo, siginfo_t *info, void *context);
//siginfo 的结构如下:
struct siginfo{
	int sig_signo;  //信号编号
	int sig_errno; //如果不是0,就是errno.h中的errno值
	int sig_code; //附加信息(取决于信号)
	pid_t si_pid; //发送信号的进程ID
	uid_t sig_uid; //发送信号的进程实际用户ID
	void *si_addr; //产生错误的地址
	int si_status; //退出值或者信号值
	long si_band; //SIGPOLL的band号
	//可能还会有其他的值。
}

下面可以  sigaction 函数实现  signal 函数的功能:

#include "apue.h"

Sigfunc *signal(int signo, Sigfunc *func)
{
    struct sigaction act, oact;

    /* 设置信号处理函数 */
    act.sa_handler = func;
    /* 初始化信号集 */
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if(signo == SIGALRM)
    {/* 若是SIGALRM信号,则系统不会自动重启 */
#ifdef SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;
#endif
    }
    else
    {/* 其余信号设置为系统会自动重启 */
#ifdef SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }
    /* 调用 sigaction 函数 */
    if(sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

测试程序:

#include 
#include "apue.h"
#include 

static Sigfunc *Msignal(int signo, Sigfunc *func);
static void sig_func(int signo);

int main(void)
{
    if(Msignal(SIGALRM,sig_func) == SIG_ERR)
        err_sys("SIGALRM error");
    if(Msignal(SIGHUP,sig_func) == SIG_ERR)
        err_sys("SIGHUP error");
    printf("kill...\n");
    kill(getpid(),SIGHUP);
    printf("alarm...\n");
    alarm(5);
    pause();
    printf("exit.\n");
    exit(0);
}

static void sig_func(int signo)
{
    if(SIGHUP == signo)
        printf("Recevied kill.\n");
    else if(SIGALRM == signo)
        printf("Recevied alarm.\n");
    else
        printf("Recevied others.\n");
}

static Sigfunc *Msignal(int signo, Sigfunc *func)
{
    struct sigaction act, oact;

    /* 设置信号处理函数 */
    act.sa_handler = func;
    /* 初始化信号集 */
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if(signo == SIGALRM)
    {/* 若是SIGALRM信号,则系统不会自动重启 */
#ifdef SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;
#endif
    }
    else
    {/* 其余信号设置为系统会自动重启 */
#ifdef SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }
    /* 调用 sigaction 函数 */
    if(sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

输出结果:

kill...
Recevied kill.
alarm...
Recevied alarm.
exit.

参考资料:

《UNIX高级环境编程》

你可能感兴趣的:(Unix,高级环境编程,UNIX高级环境编程)