// 创建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切换相关的更多相关文章

  1. Reporting Service 告警"w WARN: Thread pool pressure. Using current thread for a work item"

    如果Reporting Service偶尔出现不可访问或访问出错情况,这种情况一般没有做监控的话,很难捕捉到.出现这种问题,最好检查Reporting Service的日志文件. 今天早上就遇到这样一 ...

  2. Java 使用线程方式Thread和Runnable,以及Thread与Runnable的区别

    一. java中实现线程的方式有Thread和Runnable Thread: public class Thread1 extends Thread{ @Override public void r ...

  3. 【web前端优化之图片模糊到清晰】看我QQ空间如何显示相片

    前言 此篇文章估计不会太长,有移除首页的风险,但是老夫(称老夫是因为我们真正的叶小钗其实都100多岁啦)是不会怕滴.所以,我来了哟! 题外话:今天我们一起还看了一道前端的面试题,而后我本来还想多找几道 ...

  4. 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 ...

  5. 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 ...

  6. 严重: 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 ...

  7. Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

    第一章 Thread导论 为何要用Thread ? 非堵塞I/O      I/O多路技术      轮询(polling)      信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...

  8. 14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发

    14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发 InnoDB 使用操作系统threads 来处理用户的事务请求.(事务可以执行 ...

  9. Java 螺纹第三版 第一章Thread介绍、 第二章Thread创建和管理学习笔记

    第一章 Thread导论 为何要用Thread ? 非堵塞I/O      I/O多路技术      轮询(polling)      信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...

  10. 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 解决 ...

随机推荐

  1. windows安装wsl,在windows中使用ubuntu

    WSL(Windows Subsystem for Linux)即适用于 Linux 的 Windows 子系统,它是随 Windows 操作系统一起提供. WSL是windows操作系统的子系统,算 ...

  2. 秦皇岛2020CCPC补题

    秦皇岛2020CCPC A,E,F,G,I,K A. A Greeting from Qinhuangdao 知识点:简单题 复杂度:\(O(logn)\) #include<bits/stdc ...

  3. table 动态隐藏tr行

    table: <table style="width:100%" class="table01" cellspacing="1" ce ...

  4. 【基础语法规范】BC1:Hello Nowcoder

    语言1:Java public class Main{ public static void main(String[] args){ System.out.println("Hello N ...

  5. OpenAI 推出超神 ChatGPT 注册教程来了

    前几天,OpenAI 推出超神 ChatGPT,非常火爆.但是呢,因为不可抗力原因,大部分人无法体验到.这里我分享一下注册的攻略. 准备 首先能能访问 Google(前置条件,不能明确说,懂得都懂) ...

  6. Linux 系统用户文件缺失造成“bash-4.2$”错误的解决办法

    一.问题出现的原因 造成这个现象的原因是因为用户文件夹下的bash_logout.bash_profile和bashrc这三个隐藏文件缺失 二.问题复现 现在删除这三个文件 此时问题出现了 三.问题解 ...

  7. Qt多线程开发总览,既然用到了就记录一下

    多线程 在LBD_VM_Intercom中使用的一个简单的实例 陶工给的dll需要进行异步操作才可以将视频画面附到窗体上,必须得在画面出现之后才可以附加画面,否则就有可能出现意外bug,所以需要在这个 ...

  8. 实时采集MySQL数据之轻量工具Maxwell实操

    @ 目录 概述 定义 原理 Binlog说明 Maxwell和Canal的区别 部署 安装 MySQL准备 初始化Maxwell元数据库 Maxwell进程启动 命令行参数 配置文件 实时监控Mysq ...

  9. C++进阶(位图+布隆过滤器的概念和实现+海量数据处理)

    位图 概念 位图: 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景.通常是用来判断某个数据存不存在的. 适用场景: 如果我们需要对大量的数据进行处理,判断该数据在不在,比如40 ...

  10. 使用IntelliJ IDEA打开一个项目步骤

    目录 1.普通java项目 步骤一.使用IDEA打开一个新的项目 步骤二.设置项目的SDK 步骤三.设置项目的src为Resources Root​ 2.Maven项目 前三步同普通java项目相同 ...