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 解决 ...
随机推荐
- windows安装wsl,在windows中使用ubuntu
WSL(Windows Subsystem for Linux)即适用于 Linux 的 Windows 子系统,它是随 Windows 操作系统一起提供. WSL是windows操作系统的子系统,算 ...
- 秦皇岛2020CCPC补题
秦皇岛2020CCPC A,E,F,G,I,K A. A Greeting from Qinhuangdao 知识点:简单题 复杂度:\(O(logn)\) #include<bits/stdc ...
- table 动态隐藏tr行
table: <table style="width:100%" class="table01" cellspacing="1" ce ...
- 【基础语法规范】BC1:Hello Nowcoder
语言1:Java public class Main{ public static void main(String[] args){ System.out.println("Hello N ...
- OpenAI 推出超神 ChatGPT 注册教程来了
前几天,OpenAI 推出超神 ChatGPT,非常火爆.但是呢,因为不可抗力原因,大部分人无法体验到.这里我分享一下注册的攻略. 准备 首先能能访问 Google(前置条件,不能明确说,懂得都懂) ...
- Linux 系统用户文件缺失造成“bash-4.2$”错误的解决办法
一.问题出现的原因 造成这个现象的原因是因为用户文件夹下的bash_logout.bash_profile和bashrc这三个隐藏文件缺失 二.问题复现 现在删除这三个文件 此时问题出现了 三.问题解 ...
- Qt多线程开发总览,既然用到了就记录一下
多线程 在LBD_VM_Intercom中使用的一个简单的实例 陶工给的dll需要进行异步操作才可以将视频画面附到窗体上,必须得在画面出现之后才可以附加画面,否则就有可能出现意外bug,所以需要在这个 ...
- 实时采集MySQL数据之轻量工具Maxwell实操
@ 目录 概述 定义 原理 Binlog说明 Maxwell和Canal的区别 部署 安装 MySQL准备 初始化Maxwell元数据库 Maxwell进程启动 命令行参数 配置文件 实时监控Mysq ...
- C++进阶(位图+布隆过滤器的概念和实现+海量数据处理)
位图 概念 位图: 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景.通常是用来判断某个数据存不存在的. 适用场景: 如果我们需要对大量的数据进行处理,判断该数据在不在,比如40 ...
- 使用IntelliJ IDEA打开一个项目步骤
目录 1.普通java项目 步骤一.使用IDEA打开一个新的项目 步骤二.设置项目的SDK 步骤三.设置项目的src为Resources Root 2.Maven项目 前三步同普通java项目相同 ...