当前位置:网站首页>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
}
边栏推荐
- LeetCode刷题第16天之《239滑动窗口最大值》
- Common layout effect realization scheme
- 【yolov7系列三】实战从0构建训练自己的数据集
- 洛谷P5139 z小f的函数
- 0 Basic software test for career change, self-study for 3 months, 12k*13 salary offer
- 1815. Get the maximum number of groups of fresh donuts state compression
- Interchangeable Measurement Techniques - Geometric Errors
- Enter the starting position, the ending position intercepts the linked list
- 洛谷P1196 银河英雄传说
- 【FPGA】day22-SPI protocol loopback
猜你喜欢

JVM 垃圾回收的概述与机制

【FPGA】abbreviation

机器学习是什么?详解机器学习概念

Graphical LeetCode - 640. Solving Equations (Difficulty: Moderate)

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

Power Cabinet Data Monitoring RTU

《卫星界》刊评“星辰大海”计划:孙宇晨为太空旅游带来新的机遇

机器学习可以应用在哪些场景?机器学习有什么用?

To break the bottleneck of transactional work, the gentleman signs the electronic contract to release the "source power" of HR!

Interchangeable Measurement Techniques - Geometric Errors
随机推荐
LeetCode刷题第10天字符串系列之《125回文串验证》
关于数据分页显示
视觉任务种常用的类别文件之一json文件
【小记】BatchSize的数值是设置的越大越好吗
力扣——旋转数组的最小数字
"104 Maximum Depth of Binary Trees" in LeetCode's Day 12 Binary Tree Series
【人话版】WEB3将至之“权益的游戏”
The priority queue
Echart地图的省级,以及所有地市级下载与使用
Use jackson to parse json data in detail
洛谷P5139 z小f的函数
洛谷P2580 于是他错误的点名开始了
洛谷P2245 星际导航
MYSQLg advanced ------ clustered and non-clustered indexes
【组成原理 九 CPU】
About data paging display
es-head插件插入查询以及条件查询(五)
北湖区燕泉街道开展“戴头盔·保安全”送头盔活动
利用Navicat Premium导出数据库表结构信息至Excel
Pinduoduo store business license related issues