当前位置:网站首页>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
}
边栏推荐
猜你喜欢

The principle, architecture, implementation, practice of "transfer" and "search", no need to be afraid of interviews

"125 Palindrome Verification" of the 10th day string series of LeetCode brushing questions

LeetCode Brush Questions Day 11 String Series "58 Last Word Length"

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

Where can machine learning be applied?What is machine learning useful for?

网络安全培训机构哪家好?排名怎么选择?

"98 BST and Its Verification" of the 13th day of leetcode brushing series of binary tree series

Interchangeability Measurements and Techniques - Calculation of Deviations and Tolerances, Drawing of Tolerance Charts, Selection of Fits and Tolerance Classes

Clang Code Model: Error: The clangbackend executable “X:/clangbackend.exe“ could not be started

How to add icons to web pages?
随机推荐
洛谷P4560 Wall 砖墙
CTO said that the number of rows in a MySQL table should not exceed 2000w, why?
Switch---Spanning Tree---Three-layer Architecture Summary
【yolov7系列三】实战从0构建训练自己的数据集
Interchangeability Measurements and Techniques - Calculation of Deviations and Tolerances, Drawing of Tolerance Charts, Selection of Fits and Tolerance Classes
【人话版】WEB3将至之“权益的游戏”
Alibaba Cloud releases 3 high-performance computing solutions
UNI-APP_iphone bottom safe area
jwsManager服务接口实现类-jni实现
Power Cabinet Data Monitoring RTU
Use Navicat Premium to export database table structure information to Excel
洛谷P2580 于是他错误的点名开始了
二叉堆的基础~
【组成原理 九 CPU】
0 Basic software test for career change, self-study for 3 months, 12k*13 salary offer
对象的创建以及显示转换
拼多多店铺营业执照相关问题
网络安全培训机构哪家好?排名怎么选择?
What is ensemble learning in machine learning?
什么是机器强化学习?原理是什么?