rt-thread模糊到清晰系列: thread切换相关
// 创建thread
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
rt_thread_t rt_thread_create(const char *name,
void (*entry)(void *parameter),
void *parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)
{
struct rt_thread *thread;
void *stack_start; thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
name);
if (thread == RT_NULL)
return RT_NULL; stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
if (stack_start == RT_NULL)
{
/* allocate stack failure */
rt_object_delete((rt_object_t)thread); return RT_NULL;
} _rt_thread_init(thread,
name,
entry,
parameter,
stack_start,
stack_size,
priority,
tick); return thread;
}
thread的栈相关 (这是只是初始化时所指定的寄存器值,用于第一次调度是恢复给psp, 第二次以后的调度, psp会发生变化, 从而sp也会更新为和初始化时可能不一样的位置)
static rt_err_t _rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)
{
/* init thread list */
rt_list_init(&(thread->tlist)); thread->entry = (void *)entry;
thread->parameter = parameter; /* stack init */
thread->stack_addr = stack_start;
thread->stack_size = stack_size; /* init thread stack */
rt_memset(thread->stack_addr, '#', thread->stack_size);
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
(void *)((char *)thread->stack_addr),
(void *)rt_thread_exit);
#else
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
(rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
(void *)rt_thread_exit);
#endif
// ...
} rt_uint8_t *rt_hw_stack_init(void *tentry,
void *parameter,
rt_uint8_t *stack_addr,
void *texit)
{
struct stack_frame *stack_frame;
rt_uint8_t *stk;
unsigned long i;
// 8字节对齐,并预留末端记录寄存器结构
stk = stack_addr + sizeof(rt_uint32_t);
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
stk -= sizeof(struct stack_frame); stack_frame = (struct stack_frame *)stk; /* init all register */
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
{
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
} stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
// 返回接退出
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
// 入口
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ /* return task's current stack address */
return stk;
}
切换thread
rt_hw_context_switch_interrupt
EXPORT rt_hw_context_switch_interrupt
rt_hw_context_switch PROC
EXPORT rt_hw_context_switch ; set rt_thread_switch_interrupt_flag to 1
LDR r2, =rt_thread_switch_interrupt_flag
LDR r3, [r2]
CMP r3, #1
BEQ _reswitch
MOV r3, #1
STR r3, [r2] LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
STR r0, [r2] _reswitch
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
STR r1, [r2] LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
LDR r1, =NVIC_PENDSVSET
STR r1, [r0]
BX LR
ENDP ; r0 --> switch from thread stack
; r1 --> switch to thread stack
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
PendSV_Handler PROC
EXPORT PendSV_Handler ; disable interrupt to protect context switch
MRS r2, PRIMASK
CPSID I ; get rt_thread_switch_interrupt_flag
LDR r0, =rt_thread_switch_interrupt_flag
LDR r1, [r0]
CBZ r1, pendsv_exit ; pendsv already handled ; clear rt_thread_switch_interrupt_flag to 0
MOV r1, #0x00
STR r1, [r0] LDR r0, =rt_interrupt_from_thread
LDR r1, [r0]
CBZ r1, switch_to_thread ; skip register save at the first time MRS r1, psp ; get from thread stack pointer
STMFD r1!, {r4 - r11} ; push r4 - r11 register
LDR r0, [r0]
STR r1, [r0] ; update from thread stack pointer switch_to_thread
LDR r1, =rt_interrupt_to_thread
LDR r1, [r1]
LDR r1, [r1] ; load thread stack pointer LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
MSR psp, r1 ; update stack pointer pendsv_exit
; restore interrupt
MSR PRIMASK, r2 ORR lr, lr, #0x04
BX lr
ENDP
等价伪代码
// 设置thread的切换标志, 记录切换前后的thread的sp, 产生PendSV_Handler中断
void rt_hw_context_switch_interrupt(pp_from_thread_sp, pp_to_thread_sp)
{
if (rt_thread_switch_interrupt_flag) {
goto _reswitch;
}
rt_thread_switch_interrupt_flag = 1;
rt_interrupt_from_thread = pp_from_thread_sp; _reswitch:
rt_interrupt_to_thread = pp_to_thread_sp;
[NVIC_INT_CTRL] = NVIC_PENDSVSET;
}
// 1. 离开当前thread >>> 把当前{r4-r11}入栈,并把栈位置记录给thread中的sp
// 2. 进入新的thread >>> 1中的逆操作
void PendSV_Handler()
{
r2 = PRIMASK;
CPSID I if (!rt_thread_switch_interrupt_flag) {
goto pendsv_exit;
} rt_thread_switch_interrupt_flag = 0; // 第一次调度,还没存在要离开的thread,因此不用压栈和记录栈顶位置给sp
if (!pp_from_thread_sp) {
goto switch_to_thread;
} MRS r1, psp ; get from thread stack pointer
// r1! 代表 r1最终指向最后一个入栈之后 (没有叹号代表r1不变,即指向第一个入栈位置之前)
STMFD r1!, {r4 - r11} ; push r4 - r11 register
// stack.push(r11) stack.push(r10) ... stack.push(r4)
**pp_from_thread_sp = r1 switch_to_thread:
r1 = **pp_to_thread_sp
LDMFD r1!, {r4 - r11}
MSR psp, r1 pendsv_exit:
PRIMASK, r2
}
rt-thread模糊到清晰系列: thread切换相关的更多相关文章
- Reporting Service 告警"w WARN: Thread pool pressure. Using current thread for a work item"
如果Reporting Service偶尔出现不可访问或访问出错情况,这种情况一般没有做监控的话,很难捕捉到.出现这种问题,最好检查Reporting Service的日志文件. 今天早上就遇到这样一 ...
- Java 使用线程方式Thread和Runnable,以及Thread与Runnable的区别
一. java中实现线程的方式有Thread和Runnable Thread: public class Thread1 extends Thread{ @Override public void r ...
- 【web前端优化之图片模糊到清晰】看我QQ空间如何显示相片
前言 此篇文章估计不会太长,有移除首页的风险,但是老夫(称老夫是因为我们真正的叶小钗其实都100多岁啦)是不会怕滴.所以,我来了哟! 题外话:今天我们一起还看了一道前端的面试题,而后我本来还想多找几道 ...
- The web application [] appears to have started a thread named [Abandoned connection cleanup thread] com.mysql.jdbc.AbandonedConnectionCleanupThread
01-Jul-2016 14:25:30.937 WARNING [localhost-startStop-1] org.apache.catalina.loader.WebappClassLoade ...
- Thread message loop for a thread with a hidden window? Make AllocateHwnd safe
Thread message loop for a thread with a hidden window? I have a Delphi 6 application that has a thre ...
- 严重: The web application [] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it.
今日在重新部署项目时出现此问题,虽然对项目无影响,但问题就是问题.完整信息如下(使用idea工具): 十二月 05, 2015 11:44:27 上午 org.apache.catalina.star ...
- Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记
第一章 Thread导论 为何要用Thread ? 非堵塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...
- 14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发
14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发 InnoDB 使用操作系统threads 来处理用户的事务请求.(事务可以执行 ...
- Java 螺纹第三版 第一章Thread介绍、 第二章Thread创建和管理学习笔记
第一章 Thread导论 为何要用Thread ? 非堵塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...
- rpmdb: Thread/process 9180/139855524558592 failed: Thread died in Berkeley DB library
使用yum安装出现问题:rpmdb: Thread/process 9180/139855524558592 failed: Thread died in Berkeley DB library 解决 ...
随机推荐
- npm安装hexo报错
报错提示 npm WARN saveError ENOENT: no such file or directory, open '/home/linux1/package.json' npm noti ...
- 本地JS文件批量压缩
最近在维护一个小后台项目,有段JS需要压缩上传到CDN存储服务器.由于之前压缩的JS文件都比较少,都是手动压缩的.这次需要压缩的文件比较多,所以用了批量压缩.特此记录一下,方便大家和自己以后再用到的时 ...
- 12V转5V降压芯片,12V转3.3V稳压芯片电路图
12V转5V应用中,大多要求会输出电流高的,稳压LDO就不能满足了,需要使用DC-DC降压芯片来持续稳压5V,输出电流1000MA,2000MA,3000MA,5000MA等.不同的输出电流可以选择适 ...
- CPU 和 CPU Core 有啥区别?多核 CPU?多个 CPU?
CPU 全称 Central Processing Unit,中央处理器,计算机的大脑,长这个样子: CPU 通过一个插槽安装在主板上,这个插槽也叫做 CPU Socket,它长这个样子: 而我们说的 ...
- 使用Google OR-Tools分析过去20年中国金融资产最佳配置组合
前两天,在朋友圈里看到一张截至2022年Q2的金融资产历年收益图如下,图中列举了国内从2005年到2022年近20年主要的金融资产历年收益率,随产生想法分析和验证下面几个问题: 过去20年,基于怎样的 ...
- 一个简单的工具开发:从学生端更新程序部署工具说起,浅谈qt中自定义控件制作和调用、TCP协议下文件的收发 、以及可执行文件的打包
一个简单的工具开发:从学生端更新程序部署工具说起,浅谈qt中ui的使用和TCP协议下文件的收发.以及可执行文件的打包 写在前面,Qt Designer是一个非常操蛋的页面编辑器,它非常的...怎么说呢 ...
- STM32点亮LED的代码
led.c #include "led.h" void LED_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2P ...
- sha1_b64_scrape
过无限debugger:https://www.cnblogs.com/hkwJsxl/p/16702143.html 网站 aHR0cHM6Ly9hbnRpc3BpZGVyOC5zY3JhcGUuY ...
- 本机无法配置远程服务器上的MySQL ODBC连接驱动
1.问题描述 我想要访问远程windows服务器上的MySQL数据库,因此需要在本地ODBC驱动上配好远程服务器的MySQL.但配置好基本信息后,测试的时候出现如下问题: 2.解决方法 之所以产生这种 ...
- Redis哨兵集群搭建-Docker-Compose
title: Redis哨兵集群搭建(Docker-Compose) date: 2022-09-27 17:00:56 tags: - Redis 代码地址:https://github.com/l ...