RTthread线程间通信(邮箱,消息队列,信号/软件中断)---03信号(软件中断)源码分析
信号
实际使用看这一个
#if defined(RT_USING_SIGNALS)rt_sigset_t sig_pending; /**< the pending signals 记录来了的信号 */rt_sigset_t sig_mask; /**< the mask bits of signal 记录屏蔽的信号 */rt_sighandler_t *sig_vectors; /**< vectors of signal handler 记录处理函数 */void *si_list; /**< the signal infor list 挂起的信号的信息链表 */
#endif
线程管理结构体
typedef void (*rt_sighandler_t)(int signo);
处理函数
struct siginfo_node
{siginfo_t si;struct rt_slist_node list;
};
这一个是用来记录挂起的信号的的信息
信号的处理除了会在这里面显示的位置进行, 还会在切换任务的时候处理
安装
rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
{rt_base_t level;rt_sighandler_t old = RT_NULL;rt_thread_t tid = rt_thread_self();//看一看是不是有效的值if (!sig_valid(signo)) return SIG_ERR;level = rt_hw_interrupt_disable();if (tid->sig_vectors == RT_NULL){//这一个线程之前没有安转过rt_thread_alloc_sig(tid);}if (tid->sig_vectors){old = tid->sig_vectors[signo];if (handler == SIG_IGN) tid->sig_vectors[signo] = RT_NULL;else if (handler == SIG_DFL) tid->sig_vectors[signo] = _signal_default_handler;else tid->sig_vectors[signo] = handler;}rt_hw_interrupt_enable(level);return old;
}
void rt_thread_alloc_sig(rt_thread_t tid)
{int index;rt_base_t level;rt_sighandler_t *vectors;//获取一个足以记录处理所有信号的函数的数组vectors = (rt_sighandler_t *)RT_KERNEL_MALLOC(sizeof(rt_sighandler_t) * RT_SIG_MAX);RT_ASSERT(vectors != RT_NULL);for (index = 0; index < RT_SIG_MAX; index ++){//初始化为默认的函数vectors[index] = _signal_default_handler;}//把这一个数组记录在线程里面level = rt_hw_interrupt_disable();tid->sig_vectors = vectors;rt_hw_interrupt_enable(level);
}
//默认的函数
static void _signal_default_handler(int signo)
{LOG_I("handled signo[%d] with default action.", signo);return ;
}
删除(屏蔽)
//实际上是更新一下线程里面的屏蔽值
void rt_signal_mask(int signo)
{rt_base_t level;rt_thread_t tid = rt_thread_self();level = rt_hw_interrupt_disable();tid->sig_mask &= ~sig_mask(signo);rt_hw_interrupt_enable(level);
}
解除
void rt_signal_unmask(int signo)
{rt_base_t level;rt_thread_t tid = rt_thread_self();level = rt_hw_interrupt_disable();//改一下标志tid->sig_mask |= sig_mask(signo);/* let thread handle pended signals */if (tid->sig_mask & tid->sig_pending){//有需要处理的标志rt_hw_interrupt_enable(level);_signal_deliver(tid);}else{rt_hw_interrupt_enable(level);}
}
//根据要处理的有信号的线程的状态进行分支处理
static void _signal_deliver(rt_thread_t tid)
{rt_ubase_t level;level = rt_hw_interrupt_disable();/* thread is not interested in pended signals */if (!(tid->sig_pending & tid->sig_mask)){//没有待处理的信号rt_hw_interrupt_enable(level);return;}if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND){//这一个任务挂起了(他在等待这一个信号)/* resume thread to handle signal */rt_thread_resume(tid);/* add signal state */tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);rt_hw_interrupt_enable(level);//恢复这一个任务/* re-schedule */rt_schedule();//这时候已经看完是不是这一个信号待处理了}else{//这一个任务运行或ready中if (tid == rt_thread_self()){//是当前的在运行的任务/* add signal state */tid->stat |= RT_THREAD_STAT_SIGNAL;rt_hw_interrupt_enable(level);/* do signal action in self thread context */if (rt_interrupt_get_nest() == 0){//直接开启这一个软件线程rt_thread_handle_sig(RT_TRUE);}}else if (!((tid->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL)){//不是在运行的任务, 这个时候会为这一个任务开启一个新的栈/* add signal state 更新一下标志 */tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);/* point to the signal handle entry */tid->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;tid->sig_ret = tid->sp;//记录一下之前的栈//这一个看线程处理篇//实际处理使用的之前栈下面的一部分tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL,(void *)((char *)tid->sig_ret - 32), RT_NULL);//设置一下这一个线程返回以后的处理rt_hw_interrupt_enable(level);LOG_D("signal stack pointer @ 0x%08x", tid->sp);/* re-schedule */rt_schedule();}else{rt_hw_interrupt_enable(level);}}
}
//这是一个软件中断的线程, 如果需要执行这一个的线程不在runing状态, 会使用一个新的栈空间执行这一个线程
void rt_thread_handle_sig(rt_bool_t clean_state)
{rt_base_t level;rt_thread_t tid = rt_thread_self();struct siginfo_node *si_node;level = rt_hw_interrupt_disable();if (tid->sig_pending & tid->sig_mask){/* if thread is not waiting for signal 等一个信号的话直接返回 */if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT)){//这个时候不是在等一个信号while (tid->sig_pending & tid->sig_mask){//依次处理信号int signo, error;rt_sighandler_t handler;//获取一个待处理的信号si_node = (struct siginfo_node *)tid->si_list;if (!si_node) break;/* remove this sig info node from list */if (si_node->list.next == RT_NULL)tid->si_list = RT_NULL;//这是最后一个信号elsetid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);//记录下一个信号signo = si_node->si.si_signo;//获取标号handler = tid->sig_vectors[signo];//获取处理函数tid->sig_pending &= ~sig_mask(signo);//更新挂起的标志rt_hw_interrupt_enable(level);LOG_D("handle signal: %d, handler 0x%08x", signo, handler);if (handler) handler(signo);//执行处理函数level = rt_hw_interrupt_disable();error = -RT_EINTR;rt_mp_free(si_node); /* release this siginfo node 从内存池里面释放 *//* set errno in thread tcb */tid->error = error;}/* whether clean signal status *///这一个标志需要清除if (clean_state == RT_TRUE){tid->stat &= ~RT_THREAD_STAT_SIGNAL;}else{return;}}}rt_hw_interrupt_enable(level);
}
//非当前线程的时候线程返回时候的处理函数(软件中断)
static void _signal_entry(void *parameter)
{rt_thread_t tid = rt_thread_self();/* handle signal 处理一下信号 */rt_thread_handle_sig(RT_FALSE);/* return to thread 返回之前的在处理的任务状态 */tid->sp = tid->sig_ret;//改变栈tid->sig_ret = RT_NULL;LOG_D("switch back to: 0x%08x\n", tid->sp);tid->stat &= ~RT_THREAD_STAT_SIGNAL;//线程处理的里面分析了, 主要是切换一下运行位置以及栈rt_hw_context_switch_to((rt_ubase_t)&(tid->sp));
}
发送信号
#define sig_mask(sig_no) (1u << sig_no)
int rt_thread_kill(rt_thread_t tid, int sig)
{siginfo_t si;rt_base_t level;struct siginfo_node *si_node;if (!sig_valid(sig)) return -RT_EINVAL;LOG_I("send signal: %d", sig);si.si_signo = sig;si.si_code = SI_USER;si.si_value.sival_ptr = RT_NULL;level = rt_hw_interrupt_disable();if (tid->sig_pending & sig_mask(sig)){//这一个信号标志已经挂起了, 用这一个新的信息队列覆盖之前的信息/* whether already emits this signal? */struct rt_slist_node *node;struct siginfo_node *entry;//获取挂起的信号的信息链表si_node = (struct siginfo_node *)tid->si_list;if (si_node)node = (struct rt_slist_node *)&si_node->list;elsenode = RT_NULL;/* update sig info */for (; (node) != RT_NULL; node = node->next){//遍历当前任务待处理的所有信号信息entry = rt_slist_entry(node, struct siginfo_node, list);if (entry->si.si_signo == sig){//用新的信息覆盖memcpy(&(entry->si), &si, sizeof(siginfo_t));rt_hw_interrupt_enable(level);return 0;}}}rt_hw_interrupt_enable(level);//这时候是标志没有挂起, 或者挂起了但是没有信息处理的链表项//获取一个内存块si_node = (struct siginfo_node *) rt_mp_alloc(_rt_siginfo_pool, 0);if (si_node){rt_slist_init(&(si_node->list));//更新一下信息memcpy(&(si_node->si), &si, sizeof(siginfo_t));level = rt_hw_interrupt_disable();//把这个挂入链表里面if (tid->si_list){struct siginfo_node *si_list;//这个里面前面有节点si_list = (struct siginfo_node *)tid->si_list;rt_slist_append(&(si_list->list), &(si_node->list));}else{//前面没有, 这就是第一个tid->si_list = si_node;}/* a new signal 记录一下标志 */tid->sig_pending |= sig_mask(sig);rt_hw_interrupt_enable(level);}else{LOG_E("The allocation of signal info node failed.");}/* deliver signal to this thread */_signal_deliver(tid);return RT_EOK;
}
int rt_system_signal_init(void)
{//这一个会设置rt_mp_alloc返回的大小_rt_siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node));if (_rt_siginfo_pool == RT_NULL){LOG_E("create memory pool for signal info failed.");RT_ASSERT(0);}return 0;
}
等待信号
这一个实际是一直在等待那一个信号, 那一个信号来之前一直挂起, 不会处理其他信号
int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
{int ret = RT_EOK;rt_base_t level;rt_thread_t tid = rt_thread_self();struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL;/* current context checking */RT_DEBUG_IN_THREAD_CONTEXT;/* parameters check */if (set == NULL || *set == 0 || si == NULL ){ret = -RT_EINVAL;goto __done_return;}/* clear siginfo to avoid unknown value 清空一下, 用于记录 */memset(si, 0x0, sizeof(rt_siginfo_t));level = rt_hw_interrupt_disable();/* already pending */if (tid->sig_pending & *set) goto __done;if (timeout == 0){ret = -RT_ETIMEOUT;goto __done_int;}/* suspend self thread 把自己挂起 */rt_thread_suspend(tid);/* set thread stat as waiting for signal */tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT;/* start timeout timer */if (timeout != RT_WAITING_FOREVER){/* reset the timeout of thread timer and start it */rt_timer_control(&(tid->thread_timer),RT_TIMER_CTRL_SET_TIME,&timeout);rt_timer_start(&(tid->thread_timer));}rt_hw_interrupt_enable(level);/* do thread scheduling */rt_schedule();//返回, 可能超时或者有信号来了level = rt_hw_interrupt_disable();/* remove signal waiting flag */tid->stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;/* check errno of thread */if (tid->error == -RT_ETIMEOUT){//是超时tid->error = RT_EOK;rt_hw_interrupt_enable(level);/* timer timeout */ret = -RT_ETIMEOUT;goto __done_return;}__done://是信号来了/* to get the first matched pending signals */si_node = (struct siginfo_node *)tid->si_list;while (si_node){//遍历一下所有的节点int signo;signo = si_node->si.si_signo;if (sig_mask(signo) & *set){//是在等的这一个*si = si_node->si;LOG_D("sigwait: %d sig raised!", signo);if (si_prev) si_prev->list.next = si_node->list.next;//这一个信号的链表不在第一个else{//是第一个struct siginfo_node *node_next;if (si_node->list.next){//不是最后一个node_next = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);tid->si_list = node_next;}else{//唯一的信号tid->si_list = RT_NULL;}}/* clear pending */tid->sig_pending &= ~sig_mask(signo);//记录为这一个链表处理完了rt_mp_free(si_node);//释放一下break;}si_prev = si_node;if (si_node->list.next){//后面还有, 获取下一个si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);}else{si_node = RT_NULL;}}//while__done_int:rt_hw_interrupt_enable(level);__done_return:return ret;
}
其他
#ifdef RT_USING_SIGNALS/* check stat of thread for signal */level = rt_hw_interrupt_disable();if (rt_current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING){extern void rt_thread_handle_sig(rt_bool_t clean_state);rt_current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;rt_hw_interrupt_enable(level);/* check signal status 处理信号 */rt_thread_handle_sig(RT_TRUE);}else{rt_hw_interrupt_enable(level);}
#endif
在任务切换的时候rt_schedule里面
相关文章:
RTthread线程间通信(邮箱,消息队列,信号/软件中断)---03信号(软件中断)源码分析
信号 实际使用看这一个 #if defined(RT_USING_SIGNALS)rt_sigset_t sig_pending; /**< the pending signals 记录来了的信号 */rt_sigset_t sig_mask; /**< the mask bits of signal 记录屏蔽的信号 */rt_sigh…...
老版本labelme如何不保存imagedata
我的版本是3.16,默认英文且不带取消保存imagedata的选项。 最简单粗暴的方法就是在json文件保存时把传递过来的imagedata数据设定为None,方法如下: 找到labelme的源文件,例如:D:\conda\envs\deeplab\Lib\site-packages…...
vscode 如何修改c/c++格式化风格,大括号不换行
在Visual Studio Code(VSCode)中,若要修改C代码格式化的风格以实现大括号不换行,通常会借助于插件C/C扩展中的ClangFormat配置。以下是具体的步骤: 确保已安装了C/C扩展: 打开VSCode的扩展市场(…...
IP协议(2) 和 数据链路层协议基础
IP协议续 1.路由选择 在复杂的网络结构中,我们需要找到一个通往终点的路线,这就是路由选择 举个例子:我们在没有手机导航之前,想去一个地方得是到一个地方问一下路的方式最终找到目的地 路由的过程,其实就是样子问路的过程 1.当IP数据包到达路由器的时候,会查看目的IP 2.路由器…...
Flink-1.18.1环境搭建
下载 下载flink安装包 Index of /dist/flink/flink-1.18.1 下载flink-cdc安装包 Release Release 3.0.0 ververica/flink-cdc-connectors GitHub 安装 添加环境变量 vi ~/.bash_profile export FLINK_HOME=/home/postgres/flink/flink-1.18.1 export PATH=$PATH:$FL…...
deepin20.9安装及配置
安装deepin20.9很简单,刻录u盘 安装 一路next apt install nginx global vim-nox debian11 使用apt安装php, 使php多版本共存_debain11 php5-CSDN博客 vim LeaderF安装问题 - 知乎 debian10安装vue环境, 包括安装node.js-CSDN博客 debian安装vue3 nodejs20-CSD…...
2-2 动手学深度学习v2-损失函数-笔记
损失函数,用来衡量预测值和真实值之间的区别。是机器学习里面一个非常重要的概念。 三个常用的损失函数 L2 loss、L1 loss、Huber’s Robust loss 均方损失 L2 Loss l ( y , y ′ ) 1 2 ( y − y ′ ) 2 l(y,y^{\prime})\frac{1}{2}(y-y^{\prime})^{2} l(y,y′)21…...
非springboot 使用aop 切面
在非Spring Boot应用中使用AOP(Aspect Oriented Programming,面向切面编程)的代码实现需要依赖Spring AOP库。由于Spring AOP库并不直接支持非Spring应用,你需要将Spring AOP库作为依赖项添加到项目中,并使用Spring AO…...
MongoDB 字段中数据类型不一致序列化异常排查与处理
MongoDB 字段中数据类型不一致序列化异常排查与处理 背景如下,因为项目迁移愿意,一个使用Mongodb的业务拥有C#和Java两组Api。Java Api开发和测试都很顺利。上线一段时间后,客服反馈记录都不见了。查看数据库发现,时间字段拥有两…...
网络安全简介
网络安全: 网络安全攻击分为被动攻击和主动攻击。 1. 被动攻击:是指攻击者从网络上窃取了他人的通信内容,通常把这类的攻击称为截获,被动攻击只要有2种形式:消息内容泄漏攻击和流量分析攻击。由于攻击者没…...
【Docker】.NET Core 6.0 webapi 发布上传到Docker Desktop并启动运行访问,接口返回数据乱码解决方法
欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Docker容器》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…...
【Android Gradle 插件】自定义 Gradle 插件模块 ⑤ ( 完整总结 )
一、创建自定义插件类型模块 ( Java or Kotlin Library ) 选择 " 菜单栏 / New / New Module… " 选项 , 在 " Create New Module " 对话框中 , 选择 创建 " Java or Kotlin Library " 类型的依赖库 ; 二、手动导入相关依赖 ( Java | Groovy | …...
浅析现代计算机启动流程
文章目录 前言启动流程概述磁盘分区格式MBR磁盘GPT磁盘隐藏分区 传统BIOS引导传统BIOS启动流程 UEFI引导UEFI引导程序UEFI启动流程 引导加载程序启动操作系统相关参考 前言 现代计算机的启动是一个漫长的流程,这个流程中会涉及到各种硬件的配置与交互,包…...
七月论文审稿GPT第2.5和第3版:分别微调GPT3.5、Llama2 13B以扩大对GPT4的优势
前言 自去年7月份我带队成立大模型项目团队以来,我司至今已有5个项目组,其中 第一个项目组的AIGC模特生成系统已经上线在七月官网第二项目组的论文审稿GPT则将在今年3 4月份对外上线发布第三项目组的RAG知识库问答第1版则在春节之前已就绪至于第四、第…...
Android Studio导入项目 下载gradle很慢或连接超时
AS最常见的问题之一就是下载gradle非常慢,还经常出现下载失败的情况,没有gradle就无法build项目,所以一定要先解决gradle的下载问题,下面教大家两种常用方法 手动下载压缩包并替换 1、关闭Android Studio,复制下面的网…...
如何使用VSCode上运行Jupyter,详细案例过程出可视化图
Python作为最受AI喜欢的语言之一,我们与大家共同学习下如何在VS Code上运行Jupyter,并且用简单案例实现出图。 环境 VS Code version: 1.80.1 Python: 3.12.0 小白安装过程: 在准备好基础环境,小白心想,AI可是霸占科…...
Linux中有名管道和无名管道
无名管道基础 进程间通信介绍 常用通信方式 无名管道(pipe) 有名管道 (fifo) 信号(signal) 共享内存(mmap) 套接字(socket)过时的IPC通信方式 System V IPC 共享内存(sh…...
[SWPUCTF 2021 新生赛]easyupload1.0
发现是上传文件第一想到是文件木马 <?php eval ($_POST[123]);?>木马上传burp修改后缀发现flag里面这个是假的 我们猜想是在phpinfo我们上传<?php eval(phpinfo(););?>木马上传burp修改后缀里面 CtrlF 发现flag...
【Linux网络编程三】Udp套接字编程(简易版服务器)
【Linux网络编程三】Udp套接字编程(简易版服务器) 一.创建套接字二.绑定网络信息1.构建通信类型2.填充网络信息①网络字节序的port②string类型的ip地址 3.最终绑定 三.读收消息1.服务器端接收消息recvfrom2.服务器端发送消息sendto3.客户端端发送消息sendto4.客户端…...
【Rust】字符串,看这篇就够了
这节课我们把字符串单独拿出来讲,是因为字符串太常见了,甚至有些应用的主要工作就是处理字符串。比如 Web 开发、解析器等。而 Rust 里的字符串内容相比于其他语言来说还要多一些。是否熟练掌握 Rust 的字符串的使用,对 Rust 代码开发效率有很…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
