首页 > 代码库 > APUE: 信号相关系统调用和库函数

APUE: 信号相关系统调用和库函数

信号就是软件中断,信号提供一种处理异步事件的方法。


信号出现时按照下列方式处理:

1.忽略此信号,有两个信号不能忽略。

2.捕捉此信号,有两个信号不能被捕捉。

3.默认处理,少数默认处理是忽略,大部分默认处理是终止。


ctrl+D组合键,不是信号,只是EOF字符


linux1-31为普通信号;34-64为实时信号。

trap-l命令查看所有信号,64

信号从1开始,没有0.


SIGHUP:终端接口检测到连接断开发出该信号,

SIGINT:ctrl+c,终端中断符,一般用来停止一个失去控制的进程。

SIGQUITctrl+/,终端退出符,终止前台进程,可以重启该进程。

SIGILL:非法硬件指令,

SIGTRAP:硬件故障,

SIGABRT:进程异常终止,调用abort()库函数产生该信号。

SIGBUS:硬件故障,

SIGFPE:算数异常,除数为0或浮点溢出等产生,硬件检测然后通知内核。

SIGKILL:不能被忽略、不能被捕获,可以用来杀死任意进程。Kill-9 pid kill函数就是向进程发送该信号,杀死进程。

SIGUSR1:用户自定义信号。

SIGSEGV:无效的内存引用,硬件检测然后通知内核。

SIGUSR2:用户自定义信号。

SIGPIPE:在管道的读进程已终止后,一个进程写此管道时产生;当类型为SOCK_STREAM的套接字不再连接时进程写到套接字也产生该信号。

SIGALRM:闹钟信号,调用alarm()系统调用超时产生该信号。

SIGTERM:终止,当系统关机,init进程通常发送该信号给所有进程,等待一段时间,然后发送SIGKILL信号杀死所有进程。killpid命令默认向进程发出该信号。

SIGSTKFLT:协处理器栈故障,

SIGCHLD:子进程状态改变,当一个fork出来的子进程终止时发送一个该信号给父进程,默认忽略

SIGCONT:使暂停进程继续,默认继续,否则忽略。

SIGSTOP:停止,不能被忽略、不能被捕获默认暂停进程

SIGTSTP:ctrl+z,终端停止符,停止在shell中运行的前台进程,返回作业编号,转到后台执行。

SIGTTIN:后台读控制tty,当一个后台进程组中的进程试图读其控制终端时终端产生此信号。

SIGTTOU:后台写至控制tty,当一个后台进程组中的进程试图写到其控制终端时产生该信号。

SIGURG:紧急情况,在网络连接上传来带外数据时产生,默认忽略

SIGXCPU:超过cpu限制,

SIGXFSZ:超过文件长度限制,

SIGVTALRM:虚拟时间闹钟,调用setitimer()函数产生。

SIGPROF,梗概时间超时,

SIGWINCH:终端窗口大小改变产生,默认忽略

SIGIO:指示一个异步IO事件,默认终止/忽略

SIGPWR:电源失效或重启,失效默认终止,重启默认忽略

SIGSYS:无效系统调用,


##################################################

信号相关的系统调用

##################################################

#include<unistd.h>

intpause(void);

使调用进程挂起,直到捕捉到一个信号,返回-1.


#include<unistd.h>

unsignedintalarm(unsignedint seconds);

seconds秒之后向进程发送一个SIGALRM信号;默认动作是终止调用alarm函数的进程,如果要捕捉需要在调用alarm函数之前捕捉。

一个进程只能有一个信号;

如果调用之前已经设置了闹钟,返回上一个闹钟剩余的时间;

如果调用之前设置了闹钟,seconds=0,返回上一个闹钟的剩余时间,但是取消上一个闹钟。

否则调用成功,返回0.


#include<sys/types.h>

#include<signal.h>

intkill(pid_tpid, int sig);

往进程pid发送一个信号sig.

成功返回0,失败返回-1.


pid

>0:将信号发送给进程ID=pid的进程

==0:将信号发送给与发送进程属于同一进程组的所有进程

<0:将信号发送给进程组ID=pid绝对值的所有进程

==-1:将信号发送给系统上所有进程。


#include<signal.h>


void(*signal(intsignum, void (*handler)(int)))(int)

通过类型定义简化函数原型:

typdefvoid (*sighandler_t)(int);

sighandler_tsignal(intsignum, sighandler_t handler);

返回之前的信号处理函数地址void*,该函数有一个int参数,出错返回SIG_ERR

signum是信号的数值或名称。

Void(*handler)(int)是指向信号处理函数的指针,这个信号处理函数需要一个int参数。

handler也可以取下面值:

SIG_IGN:忽略该信号

SIG_DFL:按照默认处理信号


intsigprocmask(inthow, const sigset_t *set, sigset_t *oldest);

信号屏蔽字函数,只适用于单线程的进程。

成功返回0,失败返回-1.

oldset如果非NULLoldset返回进程当前的信号屏蔽字。

set如果非NULL,根据how来修改set中的信号屏蔽字。

set如果为NULL,信号屏蔽字不变。


how:

SIG_BLOCK:阻塞,SIGKILLSIGSTOP不能阻塞。信号屏蔽字是当前信号屏蔽字和set的并集。设置阻塞后的信号进程不处理该信号,所以该信号是未决的。

SIG_UNBLOCK:解阻塞,信号屏蔽字是当前信号屏蔽字和set的补集的交集。

SIG_SETMASK:设置掩码,信号屏蔽字是set指向的信号集。


intsigpendig(sigset_t*set);

返回阻塞的不能递送的未决信号集,通过set返回。成功返回0,失败返回-1.


#include<signal.h>

intsigaction(intsginum, const struct sigaction *act, struct sigaction *oldact);

检查或修改指定信号相关联的处理动作。

act非空,修改当前动作;oldact非空,返回上一个动作。


structsigaction{

void(*sa_handler)(int signo);

//普通信号处理函数/SIG_IGN/SIG_DFL

sigset_tsa_mask;

//设置为空集就不阻塞额外信号。

intsa_flags;

void(*sa_restorer)(void);

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

//sa_flags= SA_SIGINFO 用下面的指定实时信号处理函数.

};


sa_flags:

SA_NOCLDSTOP:

SA_NOCLDWAIT:

SA_NODEFER:

SA_ONSTACK:

SA_RESETHAND:

SA_RESTART:由此信号中断的系统调用会自动重启动。

SA_SIGINFO:提供附加信息,一个siginfo结构指针和一个指向进程上下文的标识符。


Structsiginfo {

intsi_signo;

intsi_code;根据不同的信号取不同的值。

...

};


intsigsuspend(constsigset_t *mask);

总是返回-1errno=EINTR

将进程的信号屏蔽字设置为mask,在捕捉到一个信号,或发生一个会终止该进程的信号之前,该进程被挂起;如果捕捉到一个信号,且从该信号处理程序返回,则该函数返回,且进程的信号屏蔽字恢复为调用之前的。


#include<signal.h>

intsigwaitinfo(constsigset_t *set, siginfo_t *info);


intsigtimedwait(constsigset_t *set, siginfo_t *info, const struct timespec *timeout);


structtimespec {

longtv_sec;

longtv_nsec;

};


##################################################

信号相关库函数

##################################################

#include<stdlib.h>

voidabort(void);

使异常程序终止,向调用进程发送SIGABRT信号,该函数不理会进程的阻塞和忽略,可以捕获该信号进程善后工作,最终还是会终止进程。


#include<unistd.h>

unsignedintsleep(unsignedint seconds);

使调用进程被挂起,满足下列两个条件之一就继续执行:

1.seconds指定的时间到,此时函数返回0.

2.调用进程捕捉到一个信号并从信号处理程序返回,此时函数返回剩余时间。


#include<signal.h>

intraise(intsig);

进程往自身发送信号sig

成功返回0,失败返回-1.


#include<signal.h>

信号集函数,成功返回0,失败返回-1.


intsigemptyset(sigset_t*set);

set指向的信号集置空,不包含任何信号。


intsigfillset(sigset_t*set);

set指向的信号集填满,包括所有信号。


intsigaddset(sigset_t*set, int signum);

set指向的信号集中增加signum信号


intsigdelset(sigset_t*set, int signum);

set指向的信号集中删除signum信号


intsigismember(constsigset_t *set, int signum);

测试signum是否是set指向的信号集中的信号;

真返回1,假返回0,失败返回-1.


#include<setjmp.h>

在信号处理程序中进行非局部转移应该使用下面两个函数。


intsigsetjmp(sigjmp_bufenv, int savesigs);

直接调用返回0,从siglongjmp调用返回非0.


voidsiglongjmp(sigimp_bufenv, int val);

由此跳转到sigsetjmp,并让其返回val


#include<stdlib.h>

intsystem(constchar *cmd);

posix要求system函数忽略SIGINTSIGQUIT两个信号,阻塞SIGCHLD信号。


#include<signal.h>

voidpsignal(intsigno, const char *msg);

类似于perror,输出到标准出错,msg后面自动加冒号和空格,后面是信号说明。


#include<string.h>

char*strsignal(intsigno);

类似于strerror,返回指向描述信号的字符串的指针。


#include<signal.h>

intsigwait(constsigset_t *set, int *sig);

阻塞,等待set信号集中的某一个信号产生,然后返回,同时将该信号赋给sig


#include<signal.h>

intsigqueue(pid_tpid, int sig, const union sigval value);


unionsigval {

intsival_int;

void*sival_ptr;

};


未完待续......



APUE: 信号相关系统调用和库函数