基于 uClibc (0.9.33) 和 kernel(4.15)
1. signal ( uClibc 中的定义及实现)
__sighandler_t signal (int sig, __sighandler_t handler) 其实际是基于 sigaction 来实现的。
sigaction 每个体系各自实现,对于arm体系:
libc\sysdeps\linux\arm\sigaction.c 中实现。
在 __libc_sigaction 里有:
kact.sa_restorer = choose_restorer(kact.sa_flags); 即 __default_sa_restorer
在 libc\sysdeps\linux\arm\sigrestorer.S 里有定义:
__default_sa_restorer:
mov r7, $SYS_ify(sigreturn)
swi 0x0
.fnend
即调用 sigreturn 的系统调用。
Sigaction 通过系统调用调进内核,会执行到 kernel/signal.c 中的 do_sigaction 函数,其关键动作如下:
struct task_struct *p = current, *t;
struct k_sigaction *k;
k = &p->sighand->action[sig-1];
*k = *act;
会将新的 action 保存到当前进程任务结构体中的 sighand 里。
2. kill
在 uClic 中的实现,直接调用系统调用:
int kill(pid_t pid, int sig)
{
return (__syscall_kill(pid, sig));
}
此时内核的实现:
Kernel/signal.c
SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
kill_something_info
kill_pid_info // 针对于 pid > 0 , 向指定的进程发送信息
p = pid_task(pid, PIDTYPE_PID); // 通过 pid得到要发送信号的目标进程
group_send_sig_info
check_kill_permission // 进行权限检查,是否允许给进程发送信号
do_send_sig_info
send_signal
__send_signal
complete_signal
signal_wake_up
signal_wake_up_state
set_tsk_thread_flag(t, TIF_SIGPENDING);
在 __send_signal 里的关键动作如下:是从目标进程取出 pending的信号,然后为新的信号分配一个queue, 挂到pending链表中,最后通过 sigaddset 把对应的位置1,表示有该信号pending。最后调用 complete_signal 使用 set_tsk_thread_flag(t, TIF_SIGPENDING); 表示该进程有信号要处理。
struct sigpending *pending;
struct