当前位置:网站首页>send_sig: kernel execution flow
send_sig: kernel execution flow
2022-08-11 04:29:00 【Kun Yu】
When a signal is sent to a process from the kernel or another process,内核通过调用 send_sig()、send_sig_info()、force_sig() 或 force_sig_info() function to pass it.
调用关系如下:
send_sig() -> send_sig_info() … send_signal_locked() …
force_sig() -> force_sig_info() … send_signal_locked() …
目录
内容
1. 源码流程
1.1 send_sig
发送信号
int
send_sig(int sig, struct task_struct *p, int priv)
{
return send_sig_info(sig, __si_special(priv), p);
}
||
\/
int send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p)
{
/* Make sure legacy kernel users don't send wrong values(The normal path is there check_kill_permission 中检查)*/
if (!valid_signal(sig))
// return sig <= _NSIG ? 1 : 0;
// #define _NSIG 64
return -EINVAL;
return do_send_sig_info(sig, info, p, PIDTYPE_PID); // Send signal information
}
2. 源码结构
3. 部分结构定义
kernel_siginfo
typedef struct kernel_siginfo {
__SIGINFO;
} kernel_siginfo_t;
sighand_struct
struct sighand_struct {
spinlock_t siglock;
refcount_t count;
wait_queue_head_t signalfd_wqh;
struct k_sigaction action[_NSIG];
};
pid_type
enum pid_type
{
PIDTYPE_PID,
PIDTYPE_TGID,
PIDTYPE_PGID,
PIDTYPE_SID,
PIDTYPE_MAX,
};
multiprocess_signals
struct multiprocess_signals {
sigset_t signal;
struct hlist_node node;
};
4. 扩展函数
do_send_sig_info
int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p,
enum pid_type type)
{
unsigned long flags;
int ret = -ESRCH;
if (lock_task_sighand(p, &flags)) { // 获取tsk->sighand,and acquire the spinlock(保存本地中断状态,关闭本地中断)
ret = send_signal_locked(sig, info, p, type);
send_signal_locked分析,继续往下看:
unlock_task_sighand(p, &flags); // 释放锁、Restore local interrupt status, etc
}
return ret;
}
send_signal_locked
int send_signal_locked(int sig, struct kernel_siginfo *info,
struct task_struct *t, enum pid_type type)
{
/* pid namespace init should receive SIGKILL 或 SIGSTOP? */
bool force = false;
if (info == SEND_SIG_NOINFO) {
// #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)
/* 如果从ancestor pidNamespace sent,则强制 */
force = !task_pid_nr_ns(current, task_active_pid_ns(t));
} else if (info == SEND_SIG_PRIV) {
#define SEND_SIG_PRIV ((struct kernel_siginfo *) 1)
/* Do not ignore signals generated by the kernel */
force = true;
} else if (has_si_pid_and_uid(info)) { // SIL_KILL 、SIL_CHLD 、SIL_RT
/* SIGKILL和SIGSTOPis special or hasid */
struct user_namespace *t_user_ns;
rcu_read_lock();
t_user_ns = task_cred_xxx(t, user_ns); // t->real_cred->user_ns
if (current_user_ns() != t_user_ns) {
kuid_t uid = make_kuid(current_user_ns(), info->si_uid); // Put the user namespaceuid 对映射到kuid
info->si_uid = from_kuid_munged(t_user_ns, uid); // 从kuidUser namespace creates oneuid
}
rcu_read_unlock();
/* A signal generated by the kernel? */
force = (info->si_code == SI_KERNEL);
/* 来自ancestor pid命名空间? */
if (!task_pid_nr_ns(current, task_active_pid_ns(t))) {
info->si_pid = 0;
force = true;
}
}
return __send_signal_locked(sig, info, t, type, force);
}
__send_signal_locked
static int __send_signal_locked(int sig, struct kernel_siginfo *info,
struct task_struct *t, enum pid_type type, bool force)
{
struct sigpending *pending;
struct sigqueue *q;
int override_rlimit;
int ret = 0, result;
lockdep_assert_held(&t->sighand->siglock); // lock debug is true 并且 siglock为空
result = TRACE_SIGNAL_IGNORED;
if (!prepare_signal(sig, t, force))
prepare_signal分析,继续往下看:
pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
/* Short circuit ignores the signal,Supports exact queuing of a nonrt信号,This allows us to get more detailed information on the origin of the signal */
result = TRACE_SIGNAL_ALREADY_PENDING;
if (legacy_queue(pending, sig)) // If it is unreliable(非实时)信号 并且 Suspended to the signal queue
// #define SIGRTMIN 32
goto ret;
result = TRACE_SIGNAL_DELIVERED;
/* 跳过 SIGKILL and the uselessness of kernel threads siginfo 分配 */
if ((sig == SIGKILL) || (t->flags & PF_KTHREAD))
goto out_set;
/* 如果通过 sigqueue or some other real-time mechanism to send real-time signals,则必须排队
kill() Whether to do so is implementation-defined
We try to do so,In the principle of least surprise,
But since it is not allowed when out of memory kill 以 EAGAIN 失败,
We just need to make sure that at least one signal is passed and no information structure is passed */
if (sig < SIGRTMIN)
override_rlimit = (is_si_special(info) || info->si_code >= 0);
else
override_rlimit = 0;
/* Allocate a new signal queue record - 当且仅当 t == current Only then can it be called without a lock,
Otherwise an appropriate lock must be held to prevent the target task from exiting */
q = __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit, 0);
if (q) {
list_add_tail(&q->list, &pending->list);
switch ((unsigned long) info) {
case (unsigned long) SEND_SIG_NOINFO:
clear_siginfo(&q->info);
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_USER;
q->info.si_pid = task_tgid_nr_ns(current,
task_active_pid_ns(t));
rcu_read_lock();
q->info.si_uid =
from_kuid_munged(task_cred_xxx(t, user_ns),
current_uid());
rcu_read_unlock();
break;
case (unsigned long) SEND_SIG_PRIV:
clear_siginfo(&q->info);
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_KERNEL;
q->info.si_pid = 0;
q->info.si_uid = 0;
break;
...
/* This is a silent loss of information
We still send signals,但 *info 位丢失了 */
result = TRACE_SIGNAL_LOSE_INFO;
}
out_set:
/* Pass the signal to the listenersignalfd */
signalfd_notify(t, sig);
// 如果tThe process's signal wait list is not empty
// 唤醒阻塞在tProcess's signal wait queue
sigaddset(&pending->signal, sig); // siginto the signal array
// set->sig
/* Make multiprocess signals appear when in progressfork之后 */
if (type > PIDTYPE_TGID) {
struct multiprocess_signals *delayed;
hlist_for_each_entry(delayed, &t->signal->multiprocess, node) {
sigset_t *signal = &delayed->signal;
/* Can't queue both a stop and a continue signal */
if (sig == SIGCONT) // #define SIGCONT 18
sigdelsetmask(signal, SIG_KERNEL_STOP_MASK); // Remove stop sign
else if (sig_kernel_stop(sig)) // 是否需要停止
// If it is unreliable(非实时)信号,
// 并且含有SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU其中一种
sigdelset(signal, SIGCONT); // sig放入 SIGCONT
sigaddset(signal, sig);
}
}
complete_signal(sig, t, type); // Used to quickly check for unprocessed signals later
// 调用signal_wake_up
// 线程TIF_SIGPENDING标志设为1
ret:
trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result); // tracepoint函数
return ret;
}
prepare_signal
static bool prepare_signal(int sig, struct task_struct *p, bool force)
{
struct signal_struct *signal = p->signal;
struct task_struct *t;
sigset_t flush;
if (signal->flags & SIGNAL_GROUP_EXIT) {
// #define SIGNAL_GROUP_EXIT 0x00000004 Group exit in progress
if (signal->core_state)
return sig == SIGKILL;
/*
* Process is dying,无事可做
*/
} else if (sig_kernel_stop(sig)) {
/*
* This is a stop signal,Removed from all queues SIGCONT
*/
siginitset(&flush, sigmask(SIGCONT)); // 初始化sig
flush_sigqueue_mask(&flush, &signal->shared_pending); // Removes the signal in the mask from the pending collection and queue
for_each_thread(p, t)
flush_sigqueue_mask(&flush, &t->pending);
} else if (sig == SIGCONT) {
unsigned int why;
/*
* Remove all stop signals from all queues,唤醒所有线程
*/
siginitset(&flush, SIG_KERNEL_STOP_MASK);
flush_sigqueue_mask(&flush, &signal->shared_pending);
for_each_thread(p, t) {
flush_sigqueue_mask(&flush, &t->pending);
task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); // jobctl 清除JOBCTL_STOP_PENDING标志
if (likely(!(t->ptrace & PT_SEIZED))) {
t->jobctl &= ~JOBCTL_STOPPED; // 清除JOBCTL_STOPPED标志
wake_up_state(t, __TASK_STOPPED); // 唤醒一个线程
} else
/* This function schedules stickiness ptrace 陷阱,
The trap is next TRAP_STOP 时清除,
以通知 ptracer 事件 */
ptrace_trap_notify(t); // Schedule trap notificationsptracer
}
...
return !sig_ignored(p, sig, force); // 忽略信号 Or the following four states are true
// SIGCONT、SIGCHLD、SIGWINCH、SIGURG
}
边栏推荐
猜你喜欢
Interchangeability and Measurement Technology—Surface Roughness Selection and Marking Method
如何给网页添加icon图标?
Binary tree related code questions [more complete] C language
leetCode刷题14天二叉树系列之《 110 平衡二叉树判断》
机器学习怎么学?机器学习流程
0 Basic software test for career change, self-study for 3 months, 12k*13 salary offer
【力扣】22.括号生成
Graphical LeetCode - 640. Solving Equations (Difficulty: Moderate)
"239 Sliding Window Maximum Value" on the 16th day of LeetCode brushing
Clang Code Model: Error: The clangbackend executable “X:/clangbackend.exe“ could not be started
随机推荐
关于pom.xml文件
【FPGA】SDRAM
.NET Custom Middleware
LeetCode814 Math Question Day 15 Binary Tree Series Value "814 Binary Tree Pruning"
JVM 垃圾回收的概述与机制
About data paging display
【人话版】WEB3将至之“权益的游戏”
Read the article, high-performance and predictable data center network
"239 Sliding Window Maximum Value" on the 16th day of LeetCode brushing
关于数据分页显示
洛谷P4032 火锅盛宴
Alibaba Cloud releases 3 high-performance computing solutions
快速使用UE4制作”大场景游戏“
Provincial level of Echart maps, as well as all prefecture-level download and use
WPF DataGrid 使用数据模板(2)
干货:服务器网卡组技术原理与实践
To break the bottleneck of transactional work, the gentleman signs the electronic contract to release the "source power" of HR!
set_new_handler(0)是什么意思?有什么用?
es-head plugin insert query and conditional query (5)
使用百度EasyDL实现智能垃圾箱