当前位置:网站首页>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
}
边栏推荐
- 洛谷P4847 银河英雄传说V2
- Mysql: set the primary key to automatically increase the starting value
- 二叉堆的基础~
- Interchangeability and Measurement Techniques - Tolerance Principles and Selection Methods
- 阿里云发布3大高性能计算解决方案
- Graphical LeetCode - 640. Solving Equations (Difficulty: Moderate)
- map和set--天然的搜索和查找语义
- 洛谷P1763 埃及分数
- 【深度学习】基于卷积神经网络的天气识别训练
- 关于pom.xml文件
猜你喜欢

CTO said that the number of rows in a MySQL table should not exceed 2000w, why?

Overview of the JVM garbage collection and mechanism

干货:服务器网卡组技术原理与实践

Switch---Spanning Tree---Three-layer Architecture Summary

"3 Longest Substring Without Repeating Characters" on the 17th day of LeetCode brushing

LeetCode刷题第12天二叉树系列之《104 二叉树的最大深度》

0 Basic software test for career change, self-study for 3 months, 12k*13 salary offer

leetcode刷题第13天二叉树系列之《98 BST及其验证》

LeetCode刷题第17天之《3 无重复字符的最长子串》

自研能力再获认可,腾讯云数据库入选 Forrester Translytical 报告
随机推荐
Echart地图的省级,以及所有地市级下载与使用
【组成原理 九 CPU】
The FTP error code list
Object Creation and Display Transformation
「转」“搜索”的原理,架构,实现,实践,面试不用再怕了
Enter the starting position, the ending position intercepts the linked list
.NET自定义中间件
Introduction to c # a week of high-level programming c # - LINQ Day Four
AVH 动手实践 (二) | 在 Arm 虚拟硬件上部署 PP-OCR 模型
[Server installation Redis] Centos7 offline installation of redis
"239 Sliding Window Maximum Value" on the 16th day of LeetCode brushing
"3 Longest Substring Without Repeating Characters" on the 17th day of LeetCode brushing
LeetCode刷题第11天字符串系列之《 58最后一个单词长度》
LeetCode Brush Questions Day 11 String Series "58 Last Word Length"
如何进行AI业务诊断,快速识别降本提效增长点?
LeetCode刷题第16天之《239滑动窗口最大值》
Which one to choose for mobile map development?
洛谷P1196 银河英雄传说
0基础转行软件测试,自学3个月,浅拿12k*13薪offer
洛谷P2150 寿司晚宴