Linux/UNIX之信号(2)


信号(2)

sigaction函数

sigaction函数的功能是检查或修改与制定信号相关联的处理动作。此函数取代了signal函数。

#include <signal.h>

int sigaction(int signum, const structsigaction *act, struct sigaction *oldact);

此函数使用下列结构:

struct sigaction {

void (*sa_handler)(int);

void (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer)(void);

};

返回值:若成功则返回0,如出错则返回-1。

其中参数,signum是要检测或修改其具体动作的信号编号。若oact指针非空,则将把原先对该信号的动作写到它指向的位置。若act是空指针,则sigaction函数就不需要再做其他设置了,否则将在该参数中设置对指定信号的动作。

在参数act指向的sigaction结构中,sa_handler是一个函数指针,它指向接收信号sig时将被调用的信号处理函数。它相当于前面见到的传递函数signal的参数func。我们可以将sa_handler字段设置为特殊SIG_IGN和SIG_DFL,它们分别表示信号将被忽略或把对该信号的处理方式恢复为默认动作。

sa_mask字段指定了一个信号集,在调用sa_handle所指向的信号处理函数之前,该信号集将被加入到进程的信号屏蔽字中。这是一组将被阻塞且不会被传递给该进程的信号。设置信号屏蔽字可以防止前面看到的信号在它的处理函数还未运行结束时就被接收到的情况。

下面的程序可以实现signal函数。

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) {
#ifdef SA_INTERRUPT
       act.sa_flags |= SA_INTERRUPT;
#endif
    }else {
#ifdef SA_RESTART
       act.sa_flags |= SA_RESTART;
#endif
    }
   if (sigaction(signo, &act, &oact) < 0)
       return(SIG_ERR);
   return(oact.sa_handler);
}

sigsetjmp和siglongjmp

在信号处理中进行非局部转移时,应当使用这两个函数。

#include <setjmp.h>

int sigsetjmp(sigjmp_buf env, intsavesigs);

void siglongjmp(sigjmp_buf env, int val);

这两个函数与setjmp和longjmp之间的唯一区别是sigsetjmp增加了一个参数。如果savesigs非0,则sigsetjmp在env中保存了进程的当前信号屏蔽字。调用siglongjmp时,如果带非0 savesigs的sigsetjmp调用已经保存了env,则siglongjmp从其中恢复保存的信号屏蔽字。

sigsuspend函数

#include<signal.h>

intsigsuspend(const sigset_t *mask);

将进程的信号屏蔽字设置为mask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。

absorb函数

#include<stdlib.h>

voidabort(void);

该函数使异常终止。此函数将SIGABRT信号发送给调用进程。调用abort将向主机环境传递一个为成功终止的通知,其方法是调用raise函数。abort将会冲洗所以打开的流;确保进程对此信号不阻塞,不理会进程对此信号的阻塞。

以下是POSIX.1中abort函数的实现:

#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
 
void
abort(void)         /* POSIX-style abort() function */
{
    sigset_t            mask;
    struct sigaction    action;
 
    /*
     * Caller can't ignore SIGABRT, if so resetto default.
     */
    sigaction(SIGABRT, NULL, &action);
    if (action.sa_handler == SIG_IGN) {
        action.sa_handler = SIG_DFL;
        sigaction(SIGABRT, &action, NULL);
    }
    if (action.sa_handler == SIG_DFL)
        fflush(NULL);           /* flush all open stdio streams */
/*
     * Caller can't block SIGABRT; make sureit's unblocked.
     */
    sigfillset(&mask);
    sigdelset(&mask, SIGABRT);  /* mask has only SIGABRT turned off */
    sigprocmask(SIG_SETMASK, &mask, NULL);
    kill(getpid(), SIGABRT);    /* send the signal */
 
    /*
     * If we're here, process caught SIGABRTand returned.
     */
    fflush(NULL);               /* flush all open stdio streams*/
    action.sa_handler = SIG_DFL;
    sigaction(SIGABRT, &action, NULL);  /* reset to default */
    sigprocmask(SIG_SETMASK, &mask,NULL);  /* just in case ... */
    kill(getpid(), SIGABRT);                /* and one more time */
    exit(1);   /* this should never be executed ... */
}

sleep函数

#include <unistd.h>

unsigned int sleep(unsigned int seconds);

此函数使调用进程被挂起,直到满足以下条件之一:

1. 已经过了seconds所指定的墙上时钟时间

2. 调用进程捕捉到一个信号并从信号处理程序返回

作业控制信号

6个与作业控制有关的信号:

SIGCHLD 子进程已停止或终止

SIGCONT 如果进程已停止,则使其继续运行

SIGSTOP 停止信号

SIGTSTP 交互式停止信号

SIGTTIN 后台进程组成员读控制终端

SIGTTOU 后台进程组写到控制终端

当键入挂起字符键(通常是ctrl+Z)时,SIGTSTP被送至前台进程组的所有进程。当我们通知shell在前台或后台恢复运行一个作业时,shell向该作业中的所有进程发送SIGCONT信号。

相关内容