信号底层API:sigaction
linux中信号的分类
标准信号及其不可靠性
- 标准信号
- 1-31号信号,也叫不可靠信号,继承UNIX信号,采用位图管理
- 如果同时来相同的信号来不及处理,内核会丢弃掉
- 实时信号
- 32~64号信号,是可靠的,采用队列管理
- 来一次,处理一次,转发一次
信号处理机制
内核对信号的处理
- A进程向B进程发送一个信号,内核会首先收到信号,然后发给B进程,在发送给B进程之前,内核负责管理这些信号
- 对于不可靠信号,内核采用位图标记,给该信号分配sigqueue结构体,挂入链表之中,并将位图中的对应位置一;此时若有相同的信号发来,因为对应位已经置一,因此内核会丢弃该信号
- 对于可靠信号,内核采用队列管理:给该信号分配一个sigqueue结构体,并挂入到链表队列之中
- 队列中信号的个数也是有限制的,超过默认值,可靠信号也会丢失,也就变得不可靠了。
信号底层API:sigaction
函数底层注册函数
-
函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); -
函数功能:给信号设置新的注册函数act,同时保留原有的信号处理函数在oldact
- 执行某些信号时屏蔽某些信号,直接给sa_mask赋值即可
- 处理带参数的信号
- 一次注册,长期有效
-
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
高级信号函数
新的信号发送函数
- 函数原型:int sigqueue(pid_t pid, int sig, const union sigval value);
- 函数功能:
- 用法与kill类似
- 与kill不同之处,kill可以将pid设置为指定负数,向整个进程发送信号
- 可以给指定进程传递一个int数据类型
- sigaction与sigqueue是一对CP
int main(int argc, char *argv[])
{
union sigval val;
val.sival_int = 10;
pid_t pid = atoi(argv[1]);
if (sigqueue(pid, SIGHUP, val) == -1)
{
perror("sigqueue");
exit(EXIT_FAILURE);
}
printf("current pid:%d\n", getpid());
return 0;
}
小结
- 一旦给信号交换了handler,它就一直有效
- 信号的handler存在并发访问,可重入问题
- 在信号的handler运行期间,会阻塞掉当前本身的信号
- 在handler运行期间,当前信号的多次提交可能被丢弃,只保留一次
- 除了本身信号是被阻塞的,可以通过设置,阻塞设定的一些信号
- signal是标准C定义的函数,而sigaction是POSIX接口函数
- Signal是对sigaction的封装
- 不同的架构、操作系统对信号的value、default action可能不一样
- 特殊的两个信号:SIGKILL和SIGSTOP
- 不能被忽略
- 不能安装signal handler、不能被捕捉
- 不能被阻塞
void signal_handler(int signum)
{
printf("signal_handler\n");
switch(signum)
{
case SIGHUP:
printf("get signal: SIGHUP\n");
sleep(20);
break;
case SIGINT:
printf("get signal: SIGINT\n");
break;
case SIGQUIT:
printf("get signal: SIGQUIT\n");
break;
case SIGUSR1:
printf("get signal: SIGQUIT\n");
break;
default:
printf("undefined signal\n");
}
}
void signal_sigaction(int signum, siginfo_t *parm, void *parm2)
{
printf("signal_sigaction");
switch(signum)
{
case SIGHUP:
printf("get signal: SIGHUP\n");
sleep(20);
break;
case SIGINT:
printf("get signal: SIGINT\n");
break;
case SIGQUIT:
printf("get signal: SIGQUIT\n");
break;
case SIGUSR1:
printf("get signal: SIGQUIT\n");
break;
default:
printf("undefined signal\n");
}
printf("received data: %d\n", parm->si_value);
printf("sending signal process pid: %d\n", parm->si_pid);
}
int main(int argc, char *argv[])
{
struct sigaction act, old_act;
act.sa_sigaction = signal_sigaction;
act.sa_handler = signal_handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGUSR1);
act.sa_flags = 0;
//sa_flags must be set, or it will cause core dump
//set 0 may cause signal losing
//act.sa_flags = SA_RESETHAND | SA_NODEFER;
//SA_RESETHAND: restore signal action to DEF
//SA_SIGINFO: use sa_sigaction as signal handler
//SA_NODEFER: umask sa_mask
sigaction(SIGHUP, &act, &old_act);
while(1);
return 0;
}
|