信号
函数signle:
#icnlude <signal.h>
void (*signal(int signo,void (*func)(int)))(int);
返回值:成功,返回以前的信号处理配置,出错,返回SIG_ERR
signo参数是信号名。func的值是常量SIG_IGN、常量SIG_DEL或当接到此信号后调用的函数的地址。如果指定SIG_IGN,则向内核表示忽略此信号。
(记住两个信号不能忽略SIGKILL和SIGSTOP)。如果指定SIG_DFL,则表示接到信号后的动作是系统默认动作。当指定函数地址时,信号发生时,
调用该函数,我们称这种处理为捕捉该信号。
例子:
#include <stdio.h>
#include <signal.h>
static void sig_usr(int);
int main()
{
if(signal(SIGUSR1,sig_usr)==SIG_ERR)
printf("can't catch SIGUSR1\n");
if(signal(SIGUSR2,sig_usr)==SIG_ERR)
printf("can't catch SIGUSR2\n");
for(;;)
pause();
}
static void sig_usr(int signo)
{
if(signo==SIGUSR1)
printf("received SIGUSR1\n");
else if(signo==SIGUSR2)
printf("received SIGUSR2\n");
else
printf("received signal %d\n",signo);
}
执行:
$ ./signal &
[1] 5904
$ kill -USR2 5904
received SIGUSR2
$ kill -USR1 5904
received SIGUSR1
$ kill 5904
[1]+ Terminated ./signal
因为执行的进程不捕捉SIGTERM的信号,而对该信号的系统默认动作是终止,所以当向该进程发送SIGTERM信号后,该进程就终止。
中断系统的调用:
被中断的系统调用相关的问题是必须显式地处理出错返回。典型的代码序列如下(假定一个读操作,它被中断,我们希望重启它):
again:
if((n=read(fd,buf,BUFFSIZE))<0)
{
if(errno==EINTR)
goto agin;
}
按系统而分,有的系统提供了sigaction默认方式是重启动被中断的系统调用。
可重入函数:
进程捕获到信号并对其进行处理时,进程正在执行的正常指令序列就被信号处理程序临时中断,它首先执行该信号处理程序中的
指令。
SIGCLD语义:
SIGCLD和SIGCHLD这两个信号很容易混淆。SIGCLD(没有H)是一个SystemV的一个信号名,其语义名为SIGCHLD的BSD信号不同。
BSD的SIGCHLD信号语义与其他信号的语义向类似。子进程状态改变产生此信号,父进程需要调用一个wait函数以检测发生了什么。
SystemV处理SIGCLD信号的方式不同于其他信号。如果用signal或者sigset设置信号配置,则基于SVR4的系统继承了这一具有问题色彩
的传统。对于SIGCLD的早期处理方式是:
1、如果进程明确地将信号的配置设置为SIG_IGN,则调用进程的子进程将不产生僵死进程。注意,这与其默认动作(SIG_DFL)忽略不同。
子进程在终止时,将其状态丢弃。如果调用进程随后调用一个wait函数,那么它将阻塞直到所有子进程都终止,然后该wait会返回-1,并
将其errno设置为ECHILD。(此信号的默认设置是忽略,但这不会使上述语义起作用。必须将其配置明确指定为SIG_IGN才可以)。
也可以使用sigaction可设置SA_NOCLDWAIT标志以避免进程僵死。
2、如果将SIGCLD的配置设置为捕捉,则内核立即检查是否有子进程准备好被等待,如果是这样,则调用SIGCLD处理程序。
程序一行行地不断重复输出"SIGCLD received",最后进程用完其栈空间并异常终止。
例子程序:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <signal.h>
static void sig_cld(int);
int main()
{
pid_t pid;
if(signal(SIGCLD,sig_cld)==SIG_ERR)
printf("signal error\n");
if((pid=fork())<0)
printf("fork error\n");
else if(pid==0)
{
sleep(2);
_exit(0);
}
pause();
exit(0);
}
static void sig_cld(int signo)
{
pid_t pid;
int status;
printf("SIGCLD received\n");
if(signal(SIGCLD,sig_cld)==SIG_ERR)
printf("signale error\n");
if(pid=wait(&status)<0)
printf("wait error\n");
printf("pid =%d\n",pid);
}
执行:
$ ./signal1
SIGCLD received
pid =0
此程序的问题是:在信号处理程序的开始处调用signal,按照上述第2种方式,内核检查是否有需要等待的子进程(因为我们正在
处理一个SIGCLD信号,所以确实有这种子进程),所以它产生另一个信号处理程序的调用。信号处理程序再次调用signal,整个
过程再次重复。
解决这个问题,应当在调用wait取得子进程的终止状态后再调用signal。
可靠信号术语和语义:
当产生一个信号时,内核通常在进程中以某种形式设置一个标志。
进程调用sigpending函数来判定哪些信号时设置为阻塞并处于未决状态的。
信号递送的顺序是:递送与当前进程状态有关的信号。
进程可以使用sigprocmask来检测和更改其当前信号屏蔽字。
函数kill和raise:
kill函数将信号发送给进程或者进程组。raise函数则允许进程向自身发送信号。
#include <signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
调用raise(signo);
等价于调用:kill(getpid(),signo);
函数alarm和pause:
使用alarm函数可以设置一个定时器(闹钟时间),在将来的某个时刻该定时器会超时。当
定时器超时时,产生SIGALRM信号。如果忽略或不捕捉此信号,则其默认动作时终止调用该
alarm函数的进程:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
返回值:0或者以前设置的闹钟时间的余留秒数。
参数seconds的值时产生信号SIGALRM需要经过的时钟秒数。
pause函数使进程挂起直至捕获到一个信号:
#include <unistd.h>
int pause(void);
返回值:-1,errno设置为EINTR
只有执行了一个信号处理程序并从其返回时,pause才返回。在这种情况下,pause返回-1,errno设置为EINTR。
程序中有一个读低速设备的可能阻塞的操作,我们希望超过一定时间量后就停止执行该操作:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
static void sig_alrm(int);
int main(void)
{
int n;
char line[MAXLINE];
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
printf("signal(SIGALRM) error\n");
alarm(10);
if((n=read(STDIN_FILENO,line,MAXLINE))<0)
printf("read error\n");
alarm(0);
write(STDOUT_FILENO,line,n);
exit(0);
}
static void sig_alrm(int signo)
{
}
1、如果在第一次alarm调用和read调用之间有一个竞争条件。如果内核在这两个函数调用之间使进程阻塞,不能占用处理机运行,
而其时间长度又超过闹钟时间,则read可能永远阻塞。大多数这种类型的操作使用较长的闹钟时间,例如1分钟或者更长一点,使
这种问题不会发生。
2、如果系统调用是自动重启动的,则当从SIGALRM信号处理程序返回时,read并不被中断。
下列就不用担心一个慢速的系统调用:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
static void sig_alrm(int );
static jmp_buf env_alrm;
int main(void)
{
int n;
char line[MAXLINE];
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
printf("signal(SIGALRM) error\n");
if(setjmp(env_alrm)!=0)
printf("read timeout\n");
alarm(10);
if((n=read(STDIN_FILENO,line,MAXLINE))<0)
printf("read error\n");
alarm(0);
write(STDOUT_FILENO,line,n);
exit(0);
}
static void sig_alrm(int signo)
{
longjmp(env_alrm,1);
}
信号集:
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
返回值:成功,返回0,出错,返回-1
int sigismember(const sigset_t *set,int signo);
返回值:成功,返回1,假,返回0
函数sigemptyset初始化由set指向的信号集,清除其中所有的信号。函数sigfillset初始化由set指向的信号集,使其包括所有信号。
所有应用程序在使用信号集前,要对该信号集调用sigemptyset或者sigfillset一次。这是因为C编译程序将赋初值的外部变量和静态
变量都初始化为0,而这是否与给定系统上信号集的实现相对应却不清楚。
一旦已经初始化了一个信号集,以后就可在该信号集中增、删特定的信号。函数sigaddset将一个信号添加到已有的信号集中,sigdelset则
从信号集中删除一个信号。对所有以信号集作为参数的函数,总是以信号集地址作为向其传送的参数。
sigemptyset函数将整形设置为0,sigfillset函数将整形设置为0,sigfillset函数则将整形中的各位都设置为1.这两个函数可以
在<signal.h>头文件中实现宏:
#define sigemptyset(ptr) (*(ptr)=0)
#define sigfillset(ptr) (*(ptr)=(sigset_t)0,0)
sigaddset、sigdelset和sigismember的实现原型:
#include <signal.h>
#include <errno.h>
//<signal.h> ususlly defines NSIG to include signal number 0.
#define SIGBAD(signo) ((signo)<=0 || (signo)>=NSIG)
int sigaddset(sigset_t *set,int signo)
{
if(SIGBAD(signo))
{
errno=EINVAL;
return(-1);
}
*set|=1<<(signo-1);
return(0);
}
int sigdelset(sigset_t *set,int signo)
{
if(SIGBAD(signo))
{
errno=EINVAL;
return(-1);
}
*set &= ~(1<<(signo-1));
return(0);
}
int sigismember(const sigset_t *set,int signo)
{
if(SIGBAD(signo))
{
errno=EINVAL;
return(-1);
}
return((*set & 1<<(signo-1))!=0);
}
函数sigprocmask:
调用函数sigprocmask可以检测和更改,或者同时进行检测和更改进程的信号屏蔽字。
#include <signal.h>
int sigprocmask(int how,const sigset_t *restrict set,sigset_t *restrict oset);
返回值:成功,返回0,失败,返回-1。
首先,若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回。
其此,若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。
how是可选值。SIG_BLOCK是或操作,而SIG_SETMASK是赋值操作。注意,不能阻塞SIGKILL和SIGSTOP信号。
how 说明
SIG_BLOCK 该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集。set包含了希望阻塞的附加信号
SIG_UNBLOCK 该进程的信号屏蔽字是其当前信号屏蔽字和set所指向信号集的交集。set包含了希望解除阻塞的信号
SIG_SETMASK 该进程新的信号屏蔽是set指向的值
程序是一个函数,它打印调用进程信号屏蔽字中的信号名。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
void pr_mask(const char *str)
{
sigset_t sigset;
int errno_save;
errno_save=errno;
if(sigprocmask(0,NULL,&sigset)<0)
printf("sigprocmask error\n");
else{
printf("%s",str);
if(sigismember(&sigset,SIGINT))
printf("SIGINT\n");
if(sigismember(&sigset,SIGQUIT))
printf("SIGQUIT\n");
if(sigismember(&sigset,SIGUSR1))
printf("SIGUSER1\n");
if(sigismember(&sigset,SIGALRM))
printf("SIGALRM\n");
printf("\n");
}
errno=errno_save;
}
函数sigpending:
sigpending函数返回一信号集,对于调用进程而言,其中的各信号是阻塞不能递送的,因而也一定是当前未决的。
信号集通过set参数返回。
#include <signal.h>
int sigpending(sigset_t *set);
返回值:成功,返回0,出错,返回-1.
信号:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
static void sig_quit(int);
int main(void)
{
sigset_t newmask,oldmask,pendmask;
if(signal(SIGQUIT,sig_quit)==SIG_ERR)
printf("can't catch SIGQUIT\n");
sigemptyset(&newmask);
sigaddset(&newmask,SIGQUIT);
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)
printf("SIG_BLOCK error\n");
sleep(5);//SIGQUIT here will remain pending
if(sigpending(&pendmask)<0)
printf("sigpending error\n");
if(sigismember(&pendmask,SIGQUIT))
printf("\nSIGQUIT pending\n");
if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
printf("SIG_SETMASK error\n");
printf("SIGQUIT unblocked\n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT\n");
if(signal(SIGQUIT,SIG_DFL)==SIG_ERR)
printf("can't reset SIGQUIT\n");
}
$ ./sigpending
^\
SIGQUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\Quit (core dumped)
$ ./sigpending
^\^\^\^\^\^\^\^\^\^\^\
SIGQUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\Quit (core dumped)
在休眠期间如果产生了退出信号,那么此时信号是未决的,但是不再受阻塞,所以在sigprocmask返回之前,它被递送到调用进程。
从程序的输出在中可以看出这一点:SIGQUIT处理程序(sig_quit)中的printf语句先执行,然后再执行sigprocmask之后的prinf语句。
注意可以看出系统上没有将信号进行排队。
函数sigaction:
sigaction函数的功能是检查或者修改与指定信号相关联的处理动作。此函数取代了UNIX早期版本使用signal函数。在下面用sigaction
函数实现了signal。
#include <signal.h>
int sigaction(int signo,const sigaction *restrict act,struct sigaction *restrict oact);
返回值:成功,0,出错,-1。
其中,参数signo是要检测或者修改具体动作的信号编号。
若act指针非空,则要修改其动作。
如果oact指针非空,则系统经由oact指针返回该信号的上一个动作。
struct sigaction{
void (*sa_handler)(int);//addr的信号处理程序
sigset_t sa_mask;//额外的信号屏蔽
int sa_flags;//信号的选择
void (*sa_sigaction)(int,siginfo_t *,void *);//交替处理程序
}
sa_sigaction字段是一个替代的信号处理程序,在sigaction结构中使用了SA_SIGINFO标志时,使用该信号处理程序。对于
sa_sigaction和sa_handler字段两者,实现可能使用同一存储区,所以应用只能一次使用这两个字段中的一个。
但是,如果设置了SA_SIGINFO标志,那么按下列方式调用信号处理程序:
void hangler(int signo,siginfo_t *info,void *context);
siginfo结构包含了信号产生原因的有关信息。该结构的大致样式如下所示。
struct siginfo{
int si_signo;//signal number
int si_errno;//if nonzero,errno value from <error.h>
int si_code;//additional info
pid_t si_pid;//sending process ID
uid_t si_uid;//sending process real user ID
void *si_addr;//address that caused the fault
int si_status;//exit value or signal number
union sigval si_value;//application-specific value
}
sigval联合包含下列字段:
int sival_int;
void *sival_ptr;
函数sigsetjmp和siglongjmp:
在信号处理程序中经常调用longjmp函数以返回到程序的主循环中,而不是从该处理程序返回。
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env,int savemask);
返回值:若直接调用,返回0,若从siglongjmp调用返回,则返回非0
void siglongjmp(sigjmp_buf env,int val);
与setjmp、longjmp之间的区别时sigsetjmp增加了一个参数。如果savemask非0,则sigsetjmp在env中
保存进程的当前信号屏蔽字。调用siglongjmp时如果非0savemask的sigsetjmp调用已经保存了env,则
siglongjmp从其中恢复保存的信号屏蔽字。
函数sigsuspend:
比如在信号阻塞的时候,产生一个信号,那么信号的传递就会被推迟直到对它解除了阻塞。
如果在解除阻塞时刻和pause之间确实产生了信号,可能永远不会见到该信号,这样pause就会永远阻塞。
为了纠正这个问题,需要在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。sigsuspend正好:
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
进程信号的屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或者发生了一个终止该进程的信号之前,该
进程被挂起。如果捕捉到一个信号而且从信号处理程序返回,则sigsuspend返回,并且该进程的信号屏蔽字
设置为调用sigsuspend之前的值。
注意,此函数没有成功返回值。如果它返回到调用这,则总是返回-1.并将errno设置为EINTR(表示一个被
中断的系统调用)。
保护临界区不被信号中断:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
static void sig_int(int);
int main(void)
{
sigset_t newmask,oldmask,waitmask;
printf("program start:\n");
if(signal(SIGINT,sig_int)==SIG_ERR)
printf("signal(SIGINT) error\n");
sigemptyset(&waitmask);
sigaddset(&waitmask,SIGUSR1);
sigemptyset(&newmask);
sigaddset(&newmask,SIGINT);
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)
printf("SIG_BLOCK error\n");
printf("int critical refion:");
if(sigsuspend(&waitmask)!=-1)
printf("sigsuspend error\n");
printf("after return from sigsuspend:");
if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
printf("SIG_SETMASK error\n");
printf("program exit:");
exit(0);
}
static void sig_int(int signo)
{
printf("\nin sig_int:");
}
程序用于捕捉中断信号和退出信号,但是希望仅当捕捉到退出信号时,才唤醒主例程:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
//volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值
//sig_atomic_t会保证该变量在使用或赋值时, 无论是在32位还是64位的机器上都能保证操作是原子的,
//它会根据机器的类型自动适应。
volatile sig_atomic_t quitflag;
static void sig_int(int signo)
{
if(signo==SIGINT)
printf("\ninterrupt\n");
else if(signo==SIGQUIT)
quitflag=1;
}
int main(void)
{
sigset_t newmask,oldmask,zeromask;
if(signal(SIGINT,sig_int)==SIG_ERR)
printf("signal(SIGINT) error\n");
if(signal(SIGQUIT,sig_int)==SIG_ERR)
printf("signal(SIGQUIT) error\n");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask,SIGQUIT);
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)
printf("SIG_BLOCK error\n");
while(quitflag==0)
sigsuspend(&zeromask);
quitflag=0;
if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
printf("SIG_SETMASK error\n");
exit(0);
}
函数abort:
abort函数的功能是使程序异常终止。
#include <stdlib.h>
void abort(void);
此函数将SIGABRT信号发送给调用进程(进程不应该忽略此信号)。
函数sleep、nanosleep和clock_nanosleep:
程序中的两个sleep的实现,但是它们是缺陷的:
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
返回值:0或者未休眠完的秒数
此函数使调用进程被挂起直到满足下面两个条件之一:
1、已经过了seconds所指定的强上时钟时间
2、调用进程捕获到一个信号并从信号处理程序中返回。
nanosleep函数与sleep函数类似,但提供了纳秒级的精度:
#include <time.h>
int nanosleep(const struct timespec *reqtp,struct timespec *remtp);
返回值:若休眠到要求的时间,返回0,出错,返回-1
这个函数挂起调用进程,直到要求的时间已经超时或者某个信号中断了该函数。reqtp参数用秒和纳秒指定了需要休眠的时间长度。
如果某个信号中断了休眠间隔,进程并没有终止,remtp参数指向timespec结构就会被设置为未休眠完的时间长度。如果对未休眠
完的时间并不感兴趣,可以把该参数设置为NULL。
使用相当于特定时钟的延迟时间来挂起调用线程。clock_nanosleep函数提供了这种功能:
#include <time.h>
int clock_nanosleep(clockid_t clock_id,int flags,const struct timespec *reqtp,struct timespec *remtp);
返回值:若休眠要求的时间,返回0;出错,返回错误码
clock_id参数指定了计算延迟时间基于的时钟。
flags参数用于控制延迟时相对还是绝对的。为0时表示的是相对的,为TIMER_ABSTIME,表示的是绝对的。
reqtp参数用秒和纳秒指定了需要休眠的时间长度
remtp参数指向timespec结构就会被设置为未休眠完的时间长度。如果对未休眠完的时间并不感兴趣,可以把该参数设置为NULL。
除了出错返回,调用:
//CLOCK_REALTIME : 这种时钟表示的是绝对时间, 指的是从1970年1月1月0:00到目前经过多少秒, 相当于你的linux系统中显示的时间,
// 所以这个时间是可以更改的, 当系统的时钟源被改变,或者系统管理员重置了系统时间之后,这种类型的时钟可以得到相应的调整, 对设定
//为此类型的timer是有影响的.
clock_nanosleep(CLOCK_REALTIME,0,reqtp,remtp);
和调用
nanosleep(reqtp,remtp);
效果是相同的。
函数sigqueue:
我们介绍了大部分UNIX系统不对信号排队。
使用排队信号必须做以下几个操作:
1、使用sigaction函数安装信号处理程序时指定SA_SIGINFO标志。如果没有给出这个标志,信号会被延迟,但信号
是否进入队列要取决于具体实现。
2、在sigaction结构的sa_sigaction成员中(而不是通常的sa_handler字段)提供信号处理程序。实现可能允许用户
使用sa_handler字段,但不能后取sigqueue函数发送出来的额外信息。
3、使用sigqueue函数发送信号:
#include <signal.h>
int sigqueue(pid_t pid,int signo,const union sigval value);
返回值:成功,返回0,出错,返回-1
sigqueue只能把信号发送给单个进程,可以使用value参数向信号处理程序传递整数和指针值,除此之外,sigqueue函数与
kill函数类似。
信号不能被无限排队。对于SIGQUEUE_MAX限制。到达相应的限制以后,sigqueue就会失败,将errno设为EAGAIN。
随着实时信号的增强,引入了用于应用程序的独立信号集。这些信号的编号在SIGRTMIN~SIGRTMAX之间,包括着两个限制值。
注意,这些信号的默认行为时终止进程。
行为 linux3.2.0
支持sigqueue *
对在SIGRTMIN和SIGREMAX之外的信号排队
即使调用者没使用SA_SIGINFO标志,也对信号排队 *
作业控制信号:
POSIX.1认为有以下6个作业控制有关:
SIGCHLD 子进程已停止或者终止
SIGCONT 如果进程已停止,则使其继续运行
SIGSTOP 停止信号(不能被捕捉或者忽略)
SIGTSTP 交互式停止信号
SIGTTIN 后台进程组成员读控制终端
SIGTTOU 后台进程组成员写控制终端
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#define BUFFSIZE 1024
static void sig_tstp(int signo)//SIGTSTP 信号处理程序
{
sigset_t mask;
//将光标移到左下角,重置tty模式。
//打开SIGTSTP,因为它在我们处理的时候被阻塞了。
sigemptyset(&mask);
sigaddset(&mask,SIGTSTP);
sigprocmask(SIG_UNBLOCK,&mask,NULL);
signal(SIGTSTP,SIG_DFL);//重置配置默认
kill(getpid(),SIGTSTP);//把信号发送给我们自己。
//在我们继续之前,我们不会从kill中返回。
signal(SIGTSTP,sig_tstp);//重建信号处理器
//重置tty模式,屏幕重绘
}
int main(void)
{
int n;
char buf[BUFFSIZE];
if(signal(SIGTSTP,SIG_IGN)==SIG_DFL)
signal(SIGTSTP,sig_tstp);
while((n=read(STDIN_FILENO,buf,BUFFSIZE))>0)
if(write(STDOUT_FILENO,buf,n)!=n)
printf("write error\n");
if(n<0)
printf("read error\n");
exit(0);
}
信号名和编号:
信号编号和信号名之间进行映射。某些系统提供数组:
extern char *sys_siglist[];
数组下标时信号编号,数组中的元素时指向信号名符串的指针。
可以使用psignal函数可移植地打印与信号编号对应的字符串:
#include <signal.h>
void psignal(int signo,const char *msg);
字符串msg(通常是程序名)输出到标准错误文件,后面跟随一个冒号和一个空格,再后面对该信号的说明,
最后一个是换行符。如果msg为NULL,只有信号说明部分输出到标准错误文件,该函数类似与perror。
如果在sigaction信号处理程序中有sigingo结构,可以使用psiginfo函数打印信号信息。
#include <signal.h>
void psiginfo(const siginfo_t *info,const char *msg);
如果需要信号的字符描述部分,也不需要把它写到标准错误文件中(如可以写到日志文件中),可以使用strsignal
函数,它类似于strerror:
#include <string.h>
char *strsignal(int signo);
返回值:指向描述该信号的字符串的指针
程序可以用来打印关于接受到信号的出错信息。
一个函数将信号编号映射为信号名,另一个反之:
#include <signal.h>
int sig2str(int signo,char *str);
int str2sig(const char *str,int *signo);
返回值;成功,0,失败-1.
当它们失败时,并不舍值errno。
技术不分国界