当前位置:网站首页>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
}
边栏推荐
- How to learn machine learning?machine learning process
- 阿里云发布3大高性能计算解决方案
- Redis:解决分布式高并发修改同一个Key的问题
- 使用百度EasyDL实现森林火灾预警识别
- Clang Code Model: Error: The clangbackend executable “X:/clangbackend.exe“ could not be started
- 【服务器安装mysql】centos7下使用mysql离线安装包安装mysql5.7
- 洛谷P4061 大吉大利,晚上吃鸡
- 洛谷P2580 于是他错误的点名开始了
- Get Qt installation information: including installation directory and various macro addresses
- 洛谷P4324 扭动的回文串
猜你喜欢
Read the article, high-performance and predictable data center network
一文读懂 高性能可预期数据中心网络
JVM 垃圾回收的概述与机制
Interchangeability and Measurement Technology—Surface Roughness Selection and Marking Method
CTO said that the number of rows in a MySQL table should not exceed 2000w, why?
Binary tree related code questions [more complete] C language
0基础转行软件测试,自学3个月,浅拿12k*13薪offer
干货:服务器网卡组技术原理与实践
LeetCode刷题第12天二叉树系列之《104 二叉树的最大深度》
这些云自动化测试工具值得拥有
随机推荐
Switch---Spanning Tree---Three-layer Architecture Summary
rub the heat - do not open
干货:服务器网卡组技术原理与实践
How to add icons to web pages?
力扣——青蛙跳台阶问题
Graphical LeetCode - 640. Solving Equations (Difficulty: Moderate)
Overview of the JVM garbage collection and mechanism
Provincial level of Echart maps, as well as all prefecture-level download and use
关于数据分页显示
【人话版】WEB3将至之“权益的游戏”
洛谷P4560 Wall 砖墙
What is ensemble learning in machine learning?
Alibaba Cloud releases 3 high-performance computing solutions
MYSQLg advanced ------ clustered and non-clustered indexes
Self-research capability was recognized again, and Tencent Cloud Database was included in the Forrester Translytical report
shell monitors gpu usage
洛谷P6586 蒟蒻火锅的盛宴
LeetCode刷题第17天之《3 无重复字符的最长子串》
交换机--- 生成树--三层架构总结
拼多多店铺营业执照相关问题