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里面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670657.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android9~Android13 某些容量SD卡被格式化为内部存储时容量显示错误问题的研究与解决方案

声明:原创文章,禁止转载! Android9~Android13 某些容量SD卡被格式化为内部存储时容量显示错误问题的研究与解决方案 分析Android11 系统对于EMMC/UFS作为内部存储、SD卡被格式化为内部存储、SD卡/U盘被格式化为便携式存储的不同处理 一.现象描述 实测Android9 Android10 A…

Aigtek高精度电压源什么作用

高精度电压源是一种能够提供稳定、可靠且精确的电压输出的电子设备。它在科学研究、工程应用和制造业中起着至关重要的作用。以下将详细介绍高精度电压源的作用及其在不同领域的应用。 一、工作原理 稳定性&#xff1a;高精度电压源通常采用精密的电路设计和稳压技术&#xff0…

Java开发IntelliJ IDEA2023

IntelliJ IDEA 2023是一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为Java开发人员设计。它提供了许多特色功能&#xff0c;帮助开发人员更高效地编写、测试和调试Java应用程序。以下是一些IntelliJ IDEA 2023的特色功能&#xff1a; 智能代码编辑器&…

软件系统架构的演变历史介绍

个人浅见&#xff0c;不喜勿喷&#xff0c;非常感谢。 软件系统架构的演变历史与计算机技术的发展紧密相连。从最早的单一大型计算机&#xff0c;到个人计算机的兴起&#xff0c;再到互联网和云计算的普及&#xff0c;软件系统架构经历了多次重大的变革。以下是软件系统…

探索回溯算法

前言 回溯算法称之通用解算法&#xff0c;任何问题都可以优先使用回溯算法思考&#xff0c;再进行优化改进。那要问上一句回溯算法是怎样思维方式&#xff1f; 一&#xff0c;回溯算法思想 回溯算法是一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题…

Jgit Packfile is truncated解决方案

配置方式解决 这两个配置选项是用于提高 SSH 连接稳定性的 SSH 客户端配置参数&#xff0c;它们被添加到 SSH 配置文件&#xff08;通常是 ~/.ssh/config&#xff09;中。这些参数有助于在网络不稳定或者长时间无数据交换时保持 SSH 连接不被断开。下面是每个参数的具体作用&am…

【并行编程框架】AsyncTool

文章目录 AsyncToolAsyncTool是什么&#xff1f;AsyncTool快速入门1&#xff09;导入依赖2&#xff09;自定义Worker3&#xff09;编排包装类Wrapper4&#xff09;提交任务执行5&#xff09;运行结果 并发编程常见的场景串行并行阻塞等待 - 先串行&#xff0c;后并行阻塞等待 -…

电力负荷预测 | 基于TCN的电力负荷预测(Python)———数据预处理

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 基于TCN的电力负荷预测(Python) python3.8 keras2.6.0 matplotlib3.5.2 numpy1.19.4 pandas1.4.3 tensorflow==2.6.0

浏览器提示ERR_SSL_KEY_USAGE_INCOMPATIBLE解决

ERR_SSL_KEY_USAGE_INCOMPATIBLE报错原因 ERR_SSL_KEY_USAGE_INCOMPATIBLE 错误通常发生在使用 SSL/TLS 连接时,指的是客户端和服务器之间进行安全通信尝试失败,原因是证书中的密钥用途(Key Usage)或扩展密钥用途(Extended Key Usage, EKU)与正在尝试的操作不兼容。这意味…

Unity笔记:相机移动

基础知识 鼠标输入 在Unity中&#xff0c;开发者在“Edit” > “Project Settings” > “Input Manager”中设置输入&#xff0c;如下图所示&#xff1a; 在设置了Mouse X后&#xff0c;Input.GetAxis("Mouse X")返回的是鼠标在X轴上的增量值。这意味着它会…

STM32TIM定时器(3)

文章目录 前言一、介绍部分输入捕获简介频率测量捕获比较通道主从模式输入捕获基本结构PWMI基本结构 二、代码部分使用输入捕获捕获另一个端口的PWM输入线路连接代码内容 PWMI获取频率占空比线路连接与上个案例一致代码实现 总结相关函数PSC、ARR都有1的误差 前言 这部分主要介…

Spring Boot整合新版Spring Security:Lambda表达式配置优雅安全

文章目录 1. 引言2. 项目依赖配置3. 使用Lambda表达式配置Spring Security4. 自定义身份验证逻辑5. 认证与授权注解5.1 Secured注解5.2 PreAuthorize和PostAuthorize注解 6. 总结 &#x1f389;Spring Boot整合新版Spring Security&#xff1a;Lambda表达式配置优雅安全 ☆* o(…

spring cloud stream

背景 主要解决不同消息中间件切换问题。实现不同中间件的代码解耦。 链接: 支持的中间件 后文使用kafka测试。 引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-stream</artifactId></depende…

[EFI]英特尔 猛兽峡谷NUC11BTM电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况主板 猛兽峡谷NUC11BTM 处理器 Intel Core™ i9-11900KB 处理器 已驱动内存英睿达 DDR4 16G 3200MHz*2已驱动硬盘铠侠RC20 1T已驱动显卡AMD Radeon RX 6600 XT已驱动声卡USB音频已驱动网卡以太网控制器 i225-LM已驱动无线网卡蓝牙奋威t919Sonoma以上版本自行安…

Spring Web Body 转化常见错误

在 Spring 中&#xff0c;对于 Body 的处理很多是借助第三方编解码器来完成的。例如常见的 JSON 解析&#xff0c;Spring 都是借助于 Jackson、Gson 等常见工具来完成。所以在 Body 处理中&#xff0c;我们遇到的很多错误都是第三方工具使用中的一些问题。 真正对于 Spring 而…

【C#学习路线——超详细介绍】

C#学习路线——超详细介绍 1. 介绍2. C#基础3. 进阶技术4. .NET框架核心5. 前端和桌面应用开发6. Web 后端开发7. 游戏开发8. 软件开发实践9. 性能调优和最佳实践10. 实战经验11. 持续学习 1. 介绍 C#是由微软开发的一种强类型、面向对象的编程语言&#xff0c;主要用于.NET框…

2024年 复习 HTML5+CSS3+移动web 笔记 之CSS遍 第5天

第 五 天 整个网站例 5.1 准备工作 项目目录与版心 base.css 5.2 网页制作思路 5.3 header 区域-整体布局 5.4 header区域-logo 5.5 header区域-导航 index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">&l…

掌握数据预测的艺术:线性回归模型详解

线性回归是统计学中用于建模两个或多个变量之间线性关系的一种方法,广泛应用于数据分析、机器学习等领域。从数学建模的角度出发,线性回归旨在找到一个线性方程,最好地描述自变量(或称为解释变量、特征变量)和因变量(或称为目标变量)之间的关系。本文将通过Python代码示…

网桥与网关

文章目录 概要网桥网关联系与区别参考文章 概要 网桥和网关的理解 网桥 几个名词的概念 网关 联系与区别 参考文章 如何通俗地解释什么是网桥&#xff1f; 网关到底是什么求通俗易懂讲解? 网桥&#xff1a;网桥也叫桥接器&#xff0c;是连接两个局域网的一种存储/转发…

C语言第十九弹---指针(三)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、数组名的理解 2、使用指针访问数组 3、⼀维数组传参的本质 4、冒泡排序 5、二级指针 6、指针数组 7、指针数组模拟二维数组 总结 1、数组名的理解…