news 2026/6/10 15:55:04

ysyx学习:移植rt-thread

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ysyx学习:移植rt-thread

上一期我们搞懂了yield-os.c的原理如何,我们理解 玩上下文切换的核心细节之后,我们可以把这些原理迁移到RT-Thread这个更大的操作系统中。

RT-Thread中有两个抽象层, 一个是BSP(Board Support Package), 另一个是libcpu。

负责把 RT-Thread 的线程结构(PCB)和抽象机器(AM)的上下文切换接口连接起来:调用处把目标/来源上下文地址临时放到线程的 user_data,触发 yield(),AM 回调读出这些信息并完成实际的上下文切换;另外还准备线程首次运行时的栈/参数(通过 kcontext)。

对于上下文的创建,需要先实现rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit)函数。

rt_uint8_t* rt_hw_stack_init(void* tentry, void* parameter, rt_uint8_t* stack_addr, void* texit) {

stack_addr = (rt_uint8_t*)(((uintptr_t)stack_addr + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));

stack_addr -= sizeof(temp_args);

temp_args* args = (temp_args*)stack_addr; // 在栈上保存 入口 参数 出口 等信息

// 设置参数

args->tentry = (void (*)(void*))tentry; // tentry是“接受一个 void* 参数、返回 void 的函数指针”

args->parameter = parameter;

args->texit = (void (*)(void))texit; // texit是“不接受参数、返回 void 的函数指针”

rt_uint8_t* c = (rt_uint8_t*)kcontext((Area){ stack_addr - sizeof(Area) , stack_addr }, (void*)wrap, args);

return c;

}

一开始先对齐,然后拉出栈的位置,在栈上保存 入口 参数 出口 等信息,然后使用kcontext函数(详情见之前的随笔),将控制状态寄存器mepc设置为函数的地址,当你执行mret指令的时候就会跳转到该函数中去,因此会跳转到wrap中,附带参数args。

这个wrap()函数如下,这个是包裹函数,讲义中提到让包裹函数来调用tentry, 并在tentry返回后调用texit,T-Thread会保证代码不会从texit中返回,因此我这个代码这么写。

执行入口函数,并附带上参数,执行完之后执行退出函数。

void wrap(temp_args* args) {

args->tentry(args->parameter);

args->texit();

// 不应该执行于此,RT-Thread会保证代码不会从texit中返回

while (1);

}

接下来来看main函数,main函数代码如下:

int main() {

ioe_init();

#ifdef __ISA_NATIVE__

// trigger the real initialization of IOE to

// perform SDL initialization int this main thread with large stack

io_read(AM_TIMER_CONFIG);

#endif

extern void __am_cte_init();

__am_cte_init();

extern int entry(void);

entry();

return 0;

}

先初始化一下ioe外设,在调用__am_cte_init()函数初始化cte。

void __am_cte_init() {

cte_init(ev_handler);

}

意思就是把__am_asm_trap赋值给mtvec,方便后面ecall的时候直接跳进去__am_asm_trap函数。

然后把ev_handler函数注册进回调函数中。

ev_handler函数如下:定义一个当前的线程,可以通过rt_thread_self()这个函数获取当前线程,再使用这个线程中的user_data,可以用current->user_data来使用他,为什么用这个呢,因为这个user_data它用于存放线程的私有数据, 这意味着RT-Thread中调度相关的代码必定不会使用这个成员, 因此它很适合我们用来传递from和to的信息,这里的from是当前线程,这个to是你要跳往的线程,这里的ev_handler是回调函数,当系统陷入yield的时候,执行完一些列操作(看以前的随笔)后会执行这个回调函数了。这个函数主要作用就是把当前上下文保存到from中然后利用to作为下一个上下文进行跳转。

static Context* ev_handler(Event e, Context* c) {

rt_thread_t current;

rt_ubase_t* para;

switch (e.event) {

case EVENT_YIELD:

current = rt_thread_self();

para = (rt_ubase_t*)current->user_data;

rt_ubase_t from = para[0];

rt_ubase_t to = para[1];

if (from) {

*((Context**)from) = c; //保存上下文到from中

}

c = *(Context**)to; // 返回to作为下一个上下文

break;

case EVENT_IRQ_TIMER:

return c;

default:

printf("Unhandled event ID = %d\n", e.event);

assert(0);

}

return c;

}

具体怎么上下文的切换呢,看这两个函数void rt_hw_context_switch_to(rt_ubase_t to)//切换到to的上下文

void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to)//切换到to的上下文,又要保存当前上下文到from上。

void rt_hw_context_switch_to(rt_ubase_t to) {

rt_ubase_t data[2];

rt_thread_t current = rt_thread_self();

rt_ubase_t temp_ud = current->user_data; //保存原来的 from 和 to

data[1] = to;

current->user_data = (rt_ubase_t)data;

yield();

current->user_data = temp_ud;

}

void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to) {

rt_ubase_t data[2];

rt_thread_t current = rt_thread_self();

rt_ubase_t temp_ud = current->user_data; //保存原来的 from 和 to

data[0] = from;

data[1] = to;

current->user_data = (rt_ubase_t)data;

yield();

current->user_data = temp_ud;

}

这两个函数实现起来基本差不多,使用刚刚的user_data保存完from和to之后将,切换线程,然后切换完之后再将原先的user_data数据还回去。

然后启动rt-thread,成功!!!

但是很奇怪,我每次输入完一行命令,下次那一行命令会多一个/>,之前貌似不会,不知道改了什么之后就会了。

image

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 21:20:18

MATLAB实现Canny边缘检测算法

一、算法原理与流程 Canny边缘检测算法由John F. Canny于1986年提出,其核心流程包含5个关键步骤: 高斯滤波:消除噪声干扰(使用高斯核卷积)梯度计算:通过Sobel算子计算梯度幅值和方向非极大值抑制&#xff1…

作者头像 李华
网站建设 2026/6/10 2:01:15

AI重照明技术实战指南:3步让普通照片拥有专业光影效果

AI重照明技术实战指南:3步让普通照片拥有专业光影效果 【免费下载链接】Relight 项目地址: https://ai.gitcode.com/hf_mirrors/dx8152/Relight 还在为照片光影效果不理想而烦恼?想不想让普通照片瞬间拥有专业影棚级别的光影质感?今天…

作者头像 李华
网站建设 2026/6/10 15:20:48

PingFangSC字体包:跨平台字体统一的革命性解决方案

PingFangSC字体包:跨平台字体统一的革命性解决方案 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件,包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 还在为网页在不同设备上字体显示不一致而烦…

作者头像 李华
网站建设 2026/6/10 23:25:09

3500词汇(词频版)-day1

单词释义1yo u[juː]pron. 你;你们2I[aɪ]pron. 我(主语)n. 碘(元素iodine的符号)3th e[ə]art. 这个4to[tuː]prep. 到;向;⾄;对于5a[ə]art. ⼀(个)n. 英⽂…

作者头像 李华
网站建设 2026/6/10 15:22:05

AI在前端营销和用户增长领域应用(待补充)

调研主流互联网大厂将AI技术应用于前端营销和用户增长领域的实践案例,并整理相关AI知识体系和学习路径。具体包括以下内容: 一、主流应用场景分析 智能推荐系统:用户行为分析、个性化内容推荐智能广告投放:CTR预测、广告创意生成用…

作者头像 李华
网站建设 2026/6/9 21:30:33

【2025最新】MuseScore下载安装教程:音乐创作与制谱的利器

前言 在当下音乐创作和编曲日益数字化的背景下,一款功能强大、操作直观的乐谱制作工具已成为无数音乐人、教师和学生的刚需。MuseScore 正因其免费开放、功能完善、支持多平台等特性,成为了广受欢迎的乐谱编辑软件之一。 然而,对于初次接触的…

作者头像 李华