信号

信号的位置:/usr/include/signal.h

信号的分类

  • 标准信号/不可靠信号:信号标识符1-32,不处于信号队列中,只能接收一次
  • 实时信号/可靠信号:信号标识符32-64,同一信号可以发送多次,被多次接收,存储在sigqueue中

信号的特点

  • 不可预测/随机性

  • 传送数据简单,信号描述符

信号的状态

  • generation

  • delivery

信号的产生

  • 键盘快捷键
  • 系统调用函数
  • 内核产生:硬件异常,被除数为0
    信号可以由线程产生,也可以由内核产生,但内核产生的终止信号通常是致命的

信号的响应

  • 默认:SIG_DEF通常是终止

  • 忽略:SIG_IGN

  • 用户自定义

==SIGKILL和SIGSTOP的默认行为不能修改,不能被忽略==

内核在信号中扮演的角色

当操作系统从内核态切换为用户态时,会检测==pending&~blocked==位图,如果位图置1则执行信号处理程序

多线程程序中的信号处理函数

对于多线程程序,kill函数会把信号传给每一个线程,当只有一个线程会执行信号处理函数

信号描述符

进程

  1. 记录信号是否被接受pending
  2. 记录屏蔽什么信号block
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*进程描述符*/
struct task_struct {

/* Signal handlers: */
struct signal_struct *signal;
struct sighand_struct __rcu *sighand; /*信号处理函数*/
sigset_t blocked; /*64位屏蔽信号字*/
sigset_t real_blocked;
/* Restored if set_restore_sigmask() was used: */
sigset_t saved_sigmask;
struct sigpending pending; /*未决信号集合*/
unsigned long sas_ss_sp; /*信号处理函数的栈地址*/
size_t sas_ss_size; /*信号处理函数的栈空间大小*/
unsigned int sas_ss_flags;

};

sighand信号处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*信号处理函数*/
struct sigaction {
__sighandler_t sa_handler;/*处理函数*/
unsigned long sa_flags; /*决定函数如何执行*/
sigset_t sa_mask; /* mask last for extensibility */
};
struct k_sigaction {
struct sigaction sa;
};

/*信号处理*/
struct sighand_struct {
spinlock_t siglock;//旋转锁,保护hander
refcount_t count; //共享此结构体的线程数
wait_queue_head_t signalfd_wqh;
struct k_sigaction action[64];//每个信号对应的处理函数
};

进程task_struct包含成员sighand_struct,成员sighangd_struct包含一个64位的数组

其中k_sigaction是仅内核可见的部分

image-20230924133956541

未决信号集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*sigset_t:64位的位图*/
typedef struct {
unsigned long sig[2];
} sigset_t;

//未决信号位图
struct sigpending {
struct list_head list;
sigset_t signal;
};
struct sigqueue {
struct list_head list;
int flags;
kernel_siginfo_t info;
struct ucounts *ucounts;
};

信号屏蔽字blocked和未决信号集pending都是sig_set(64位的位图),使用unsigned int[2]表示

可靠信号多次发送后,会存储在未决信号链sigqueue中,双向链表节点存放着64位的信号位图

共享未决信号集和私有未决信号集

信号结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct signal_struct {

refcount_t sigcnt;
atomic_t live;
int nr_threads;
struct list_head thread_head;

wait_queue_head_t wait_chldexit; /* for wait4() */

/* current thread group signal load-balancing target: */
struct task_struct *curr_target;

/* shared signal handling: */
struct sigpending shared_pending;

/* For collecting multiprocess signals during fork */
struct hlist_head multiprocess;
}

signal_struct被同一线程组所共享

信号相关调用

用户级别的系统调用

Kill

kill:向进程发送信号

1
2
3
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid
pid>0 sent to the process with the ID specified by pid. 给指定pid的线程发送信号
pid=0 sent to every process in the process group of the calling process 给当前进程所在进程组的其他进程发送信号
pid=-1 sent to every process for which the calling process has permission to send signals, except for process 1 给允许接受当前进程发送的信号的进程发送信号,init进程除外
pid<-1 sent to every process in the process group whose ID is -pid. 给进程号为-pid的进程发送信号

返回值:成功返回0,失败返回-1

error

error explain
EINVAL 无效信号值(invalid)
EPERM 无权限发送(permission)
ESRCH 目标进程不存在(search)

signal

signal:设置信号的处理程序

1
2
3
 #include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
1
void ( *signal(int signum, void (*handler)(int)) ) (int);

signal在不同unix版本中实现并不相同,signal更适合将信号的处理程序设置为忽略或则默认行为,建议使用sigaction替代signal

返回值:返回之前信号执行程序的返回值或者SIG_ERR

sigaction

sigaction:检测或修改信号处理程序

sigaction可携带siginfo,拥有更多的信息

1
2
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
1
2
3
4
5
6
7
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask; /*屏蔽信号作用*/
int sa_flags;
void (*sa_restorer)(void);
};

在一些体系中,sa_handler和sa_sigaction可能是共用体

通常,信号程序函数不使用第三个参数。

sa_flag的取值

SA_NOCLDSTOP If signum is SIGCHLD,do not receive notification when child processes stop 子进程结束后父进程不收到信号
SA_NOCLDWAIT If signum is SIGCHLD, do not transform children into zombies when they terminate. 父进程结束,子进程不变成僵尸态
SA_NODEFER Do not add the signal to the thread’s signal mask while the handler is executing, unless the signal is specified in act.sa_mask.
SA_ONSTACK Call the signal handler on an alternate signal stack provided by sigaltstack(2). 为函数指定栈空间
SA_RESETHAND Restore the signal action to the default upon entry to the signal handler. 恢复默认信号处理函数
SA_SIGINFO The signal handler takes three arguments 让hander强制接受三个参数,即使用sa_action

siginfo_t

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID 目标进程的ID*/
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
union sigval si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count;
POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault 默认执行程序的地址*/
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
void *si_lower; /* Lower bound when address violation
occurred (since Linux 3.19) */
void *si_upper; /* Upper bound when address violation
occurred (since Linux 3.19) */
int si_pkey; /* Protection key on PTE that caused
fault (since Linux 4.6) */
void *si_call_addr; /* Address of system call instruction
(since Linux 3.5) */
int si_syscall; /* Number of attempted system call
(since Linux 3.5) */
unsigned int si_arch; /* Architecture of attempted system call
(since Linux 3.5) */
}

返回值:成功返回0,失败返回-1

pause

等待一个信号的到来

abort

alarm

定时发送,被打断剩余时间会存起来

sleep

nanosleep

sigprocmask

sigsupen

信号集处理函数

sigaddset

sigfillset

sigaddsetmask

sigdelsetmask

sigemptyset

sigismember