当一个信号从内核或另一个进程发送到一个进程时,内核通过调用 send_sig()、send_sig_info()、force_sig() 或 force_sig_info() 函数来传递它。
调用关系如下:
  send_sig() -> send_sig_info() … send_signal_locked() …
  force_sig() -> force_sig_info() … send_signal_locked() …

目录

1. 源码流程

1.1 send_sig

2. 源码结构

3. 部分结构定义

4. 扩展函数

内容

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)
{/* 确保遗留内核用户不发送错误值(正常路径在 check_kill_permission 中检查)*/if (!valid_signal(sig))// return sig <= _NSIG ? 1 : 0;// #define _NSIG           64return -EINVAL;return do_send_sig_info(sig, info, p, PIDTYPE_PID); // 发送信号信息
}

do_send_sig_info分析

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,并且获取自旋锁(保存本地中断状态,关闭本地中断)ret = send_signal_locked(sig, info, p, type);

send_signal_locked分析,继续往下看:

                 unlock_task_sighand(p, &flags); // 释放锁、恢复本地中断状态等}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 是否应该接收 SIGKILL 或 SIGSTOP? */bool force = false;if (info == SEND_SIG_NOINFO) {// #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)/* 如果从ancestor pid命名空间发送,则强制 */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)/* 不要忽略内核生成的信号 */force = true;} else if (has_si_pid_and_uid(info)) { // SIL_KILL 、SIL_CHLD 、SIL_RT/* SIGKILL和SIGSTOP是特殊的或有id */struct user_namespace *t_user_ns;rcu_read_lock();t_user_ns = task_cred_xxx(t, user_ns); // t->real_cred->user_nsif (current_user_ns() != t_user_ns) {kuid_t uid = make_kuid(current_user_ns(), info->si_uid); // 将用户名称空间uid 对映射到kuidinfo->si_uid = from_kuid_munged(t_user_ns, uid); // 从kuid用户名称空间创建一个uid}rcu_read_unlock();/* 内核生成的信号? */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分析

__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); // 锁调试为真 并且 siglock为空result = TRACE_SIGNAL_IGNORED;if (!prepare_signal(sig, t, force))

prepare_signal分析,继续往下看:

pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;/* 短路忽略信号,支持精确排队一个非rt信号,让我们可以得到更详细的信号成因信息 */
result = TRACE_SIGNAL_ALREADY_PENDING;
if (legacy_queue(pending, sig)) // 如果是不可靠(非实时)信号 并且 已挂起到信号队列
// #define SIGRTMIN        32goto ret;result = TRACE_SIGNAL_DELIVERED;
/* 跳过 SIGKILL 和内核线程的无用 siginfo 分配 */
if ((sig == SIGKILL) || (t->flags & PF_KTHREAD))goto out_set;/* 如果通过 sigqueue 或其他一些实时机制发送实时信号,则必须排队kill() 是否这样做是由实现定义的我们尝试这样做,本着最小意外的原则,但是由于在内存不足时不允许 kill 以 EAGAIN 失败,我们只需确保至少传递一个信号并且不传递信息结构 */
if (sig < SIGRTMIN)override_rlimit = (is_si_special(info) || info->si_code >= 0);elseoverride_rlimit = 0;/* 分配一个新的信号队列记录 - 当且仅当 t == current 时才可以在没有锁的情况下调用它,否则必须持有适当的锁以阻止目标任务退出 */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;.../* 这是一种无声的信息丢失我们仍然发送信号,但 *info 位丢失了 */result = TRACE_SIGNAL_LOSE_INFO;}out_set:/* 将信号传递给监听signalfd */signalfd_notify(t, sig); // 如果t进程的信号等待列表不为空// 唤醒阻塞在t进程的信号等待队列sigaddset(&pending->signal, sig); // sig放入信号数组// set->sig/* 让多进程信号出现在正在进行的fork之后 */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         18sigdelsetmask(signal, SIG_KERNEL_STOP_MASK); // 删除停止标志else if (sig_kernel_stop(sig)) // 是否需要停止// 如果是不可靠(非实时)信号,// 并且含有SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU其中一种sigdelset(signal, SIGCONT); //  sig放入 SIGCONTsigaddset(signal, sig);}}complete_signal(sig, t, type); // 用于之后快速检测是否有未处理的信号// 调用signal_wake_up// 线程TIF_SIGPENDING标志设为1ret: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 正在进行组退出if (signal->core_state)return sig == SIGKILL;/** 进程处于濒死状态,无事可做*/} else if (sig_kernel_stop(sig)) {/** 这是一个停止信号,从所有队列中删除 SIGCONT*/siginitset(&flush, sigmask(SIGCONT)); // 初始化sigflush_sigqueue_mask(&flush, &signal->shared_pending); // 从待处理的集合和队列中删除掩码中的信号for_each_thread(p, t)flush_sigqueue_mask(&flush, &t->pending);} else if (sig == SIGCONT) {unsigned int why;/** 从所有队列中移除所有停止信号,唤醒所有线程*/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/* 此函数安排粘性 ptrace 陷阱,该陷阱在下一个 TRAP_STOP 时清除,以通知 ptracer 事件 */ptrace_trap_notify(t); // 安排陷阱通知ptracer}...return !sig_ignored(p, sig, force); // 忽略信号 或下面四种状态为真// SIGCONT、SIGCHLD、SIGWINCH、SIGURG
}

send_sig: 内核执行流程相关推荐

  1. Postgresql源码(66)insert on conflict语法介绍与内核执行流程解析

    相关: <Postgresql源码(66)insert on conflict语法介绍与内核执行流程解析>) <Postgresql源码(70)逻辑复制DecodeXLOG主要流程和 ...

  2. linux内核启动过程2:保护模式执行流程

    上一篇<<linux内核压缩制作bzImage>>分析了bzImage制作流程,本篇继续分析内核启动过程,从实模式跳转到保护模式及后续执行流程. protected_mode_ ...

  3. 一文弄懂printf函数从用户态到内核态的执行流程

    目录 1.简介 2.示例代码 3.程序执行初探 4.用户态处理流程 5.内核态处理流程 5.1. 软中断处理 5.2 系统调用返回 5.3 系统调用处理 5.4 stdout重定向到console 5 ...

  4. 【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )

    文章目录 一.do_mmap 函数执行流程 二.do_mmap 函数源码 调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 & ...

  5. 【内核】linux内核启动流程详细分析【转】

    转自:http://www.cnblogs.com/lcw/p/3337937.html Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件 ...

  6. 【内核】linux内核启动流程详细分析

    Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件,包括内核入口ENTRY(stext)到start_kernel间的初始化代码, 主要作用 ...

  7. UBOOT添加命令的执行流程

    BootLoader(引导装载程序)是嵌入式系统软件开发的第一个环节,它把操作系统和硬件平台衔接在一起,对于嵌入式系统的后续软件开发十分重要,在整个开发中也占有相当大的比例.U-BOOT是当前比较流行 ...

  8. Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发

    Windows异常学习笔记(二)-- 内核异常处理流程&用户异常分发 用户层与内核层异常 内核异常 分析 KiDispatchException 分析 RtlDispatchException ...

  9. CPU和软件模拟异常的执行流程

    文章目录 CPU异常记录 异常的分类 CPU产生的异常 软件模拟产生的异常 CPU异常的处理流程 CommonDispatchException函数分析 总结 模拟异常记录 模拟异常的执行流程 Rai ...

最新文章

  1. java 操作uart串口_【tty】应用程序调用write写串口调用流程
  2. 使用Python获取Linux系统的各种信息
  3. 香农信息熵之可怜的小猪
  4. python报错cannot import name ‘BeautifulSoup‘ from ‘bs4‘
  5. 基于JAVA+SpringMVC+Mybatis+MYSQL的实验室设备管理系统
  6. JAVA数据库连接池的工作机制
  7. HTML注册页面代码
  8. 2022年中国工业机器人市场现状研究分析与发展前景预测报告
  9. LIFELONG LEARNING WITH DYNAMICALLY EXPANDABLE NETWORKS论文阅读+代码解析
  10. 【云片网】使用云片网发送注册短信验证码
  11. 射频加热原理及其参数
  12. silverlight ajax调用,基于RIA的AJAX和Silverlight研究与应用
  13. 如何使用Python的第三方库you-get下载视频
  14. 如何将图片一键重命名按顺序_图片批量重命名工具(RenameIt)
  15. 勇者与羁绊 游戏开发日志(一)
  16. C#基于WindowsMediaPlayer实现音视频文件播放器
  17. android毗邻(Pilin)即时聊天应用源码
  18. 【例题收藏】◇例题·I◇ Snuke's Subway Trip
  19. java计算机毕业设计智慧门诊综合管理系统源码+mysql数据库+系统+部署+lw文档
  20. phpcms默认模板目录解析

热门文章

  1. YTA pk IPFS 蜜蜂科技深度详解王东临与YottaChain去中心化存储
  2. springCloud(微服务)基础及五大组件
  3. 阿里云、腾讯云、华为云、百度云、谷歌各平台图像识别哪个好?该用哪个大厂平台给图片打标?
  4. JS中encodeURI()和encodeURIComponent()的区别
  5. 在Word从指定页插入页眉 页眉内容自动填充为章节标题
  6. 【多线程】线程池里边都有些什么东西呢
  7. 微信为何先推出mac版本而后推出windows版本
  8. 如何使用CSDN-markdown编辑器
  9. android 仿华为手机悬浮窗设计
  10. 微信小程序开发,闪云科技小程序代理