Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread一般讨论
rt-thread线程切换过程分析
发布于 2010-09-19 23:13:06 浏览:5965
订阅该版
```rt-thread线程切换过程分析(rwen) 发这里希望各位大侠帮忙看看理解有没问题,非常感谢。 基于s3c2410,其他arm系列应该类似的 1、线程创建 线程由struct rt_thread表示。 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_malloc(stack_size); //初始化 _rt_thread_init(thread, name, entry, parameter, stack_start, stack_size, priority, tick); return thread; } 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) { /* set thread id and init thread list */ thread->tid = thread; 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); thread->sp = (void*)rt_hw_stack_init(thread->entry, thread->parameter, (void *) ((char *)thread->stack_addr + thread->stack_size - 4), (void*)rt_thread_exit); /* priority init */ RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX); thread->init_priority = priority; thread->current_priority = priority; /* tick init */ thread->init_tick = tick; //线程可运行的tick计数 thread->remaining_tick = tick; /* init user data */ thread->user_data = 0; //线程定时器,用于唤醒睡眠时的唤醒 /* init thread timer */ rt_timer_init(&(thread->thread_timer), thread->name, rt_thread_timeout, thread, 0, RT_TIMER_FLAG_ONE_SHOT); return RT_EOK; } //栈的初始化 rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit) { rt_uint32_t *stk; stk = (rt_uint32_t*)stack_addr; //栈地址,返回给thread->sp *(stk) = (rt_uint32_t)tentry; /* entry point */ //入口函数 //线程退出时执行的函数,lr是arm的子例程的返回地址,所以在entry退出时,该函数会执行 *(--stk) = (rt_uint32_t)texit; /* lr */ *(--stk) = 0; /* r12 */ *(--stk) = 0; /* r11 */ *(--stk) = 0; /* r10 */ *(--stk) = 0; /* r9 */ *(--stk) = 0; /* r8 */ *(--stk) = 0; /* r7 */ *(--stk) = 0; /* r6 */ *(--stk) = 0; /* r5 */ *(--stk) = 0; /* r4 */ *(--stk) = 0; /* r3 */ *(--stk) = 0; /* r2 */ *(--stk) = 0; /* r1 */ *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ //r0 entry传入参数 *(--stk) = SVCMODE; /* cpsr */ *(--stk) = SVCMODE; /* spsr */ /* return task's current stack address */ return (rt_uint8_t *)stk; //栈地址,返回给thread->sp } //线程退出,回收资源 static void rt_thread_exit() { struct rt_thread* thread; register rt_base_t temp; /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* get current thread */ thread = rt_current_thread; //从运行队列中删除 /* remove from schedule */ rt_schedule_remove_thread(thread); /* change stat */ thread->stat = RT_THREAD_CLOSE; //状态 /* release thread timer */ rt_timer_detach(&(thread->thread_timer)); /* enable interrupt */ rt_hw_interrupt_enable(temp); if (rt_object_is_systemobject((rt_object_t)thread) == RT_EOK) { rt_object_detach((rt_object_t)thread); } //切换到下一个线程 /* switch to next task */ rt_schedule(); } 2.1、线程切换 void rt_schedule() { register rt_uint8_t number; register rt_base_t level; register rt_uint8_t highest_ready_priority; struct rt_thread *to_thread; struct rt_thread *from_thread; /* disable interrupt */ level = rt_hw_interrupt_disable(); /* check the scheduler is enabled or not */ if (rt_scheduler_lock_nest == 0) { //在位图数组中找出有可运行线程的最高优先级队列 /* find out the highest priority task */ if (rt_thread_ready_priority_group & 0xff) { number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff]; } else if (rt_thread_ready_priority_group & 0xff00) { number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8; } else if (rt_thread_ready_priority_group & 0xff0000) { number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16; } else { number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24; } #if RT_THREAD_PRIORITY_MAX > 32 highest_ready_priority = (number << 3) + rt_lowest_bitmap[rt_thread_ready_table[number]]; #else highest_ready_priority = number; #endif //取出最高优先级队列中的第一个线程,O(1)复杂度 /* get switch to thread */ to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next, struct rt_thread, tlist); /* if the destination thread is not the same as current thread */ if (to_thread != rt_current_thread) { rt_current_priority = highest_ready_priority; from_thread = rt_current_thread; //被切换出去的是当前线程 rt_current_thread = to_thread; /* switch to new thread */ if (rt_interrupt_nest == 0) { //线程切换 rt_hw_context_switch((rt_uint32_t)&from_thread->sp, (rt_uint32_t)&to_thread->sp); } else { //在中断上下文中切换 rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp, (rt_uint32_t)&to_thread->sp); } } } /* enable interrupt */ rt_hw_interrupt_enable(level); } /* * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); * r0 --> from * r1 --> to */ .globl rt_hw_context_switch rt_hw_context_switch: //保存被切换出来的线程的下一条指令地址,下一次该线程被执行时,将从这里开始 stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) //保存寄存器,再一次保存lr,参考栈初始化函数,栈空间对应的寄存器位置 stmfd sp!, {r0-r12, lr} @ push lr & register file mrs r4, cpsr stmfd sp!, {r4} @ push cpsr mrs r4, spsr stmfd sp!, {r4} @ push spsr //保存当前线程栈指针 str sp, [r0] @ store sp in preempted tasks TCB //载入新切换进来的线程的栈指针,参考栈初始化函数rt_hw_stack_init,注意各个栈空间各位置的值 ldr sp, [r1] @ get new task stack pointer 从栈中弹出spsr/cpsr ldmfd sp!, {r4} @ pop new task spsr msr spsr_cxsf, r4 ldmfd sp!, {r4} @ pop new task cpsr msr cpsr_cxsf, r4 //弹出其他寄存器,注意这里,对于新创建的线程,pc对应于thread->entry,就是线程的切入点, // 所以下面ldmfd执行完成后,系统将继续执行新线程的thread->entry //lr对应于rt_thread_exit,即是说,该线程退出时,该函数会执行。 // 对于已经执行过的,再次被换入的线程,将从rt_hw_context_switch的下一条指令开始执行 ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc 2.2 在中断中切换?```
查看更多
5
个回答
默认排序
按发布时间排序
bernard
2010-09-20
这家伙很懒,什么也没写!
不错 [s:187] 另外关于汇编部分的解析,在编程指南中讲解。C部分就没有了,C部分有英文的注释。
rwen2012
2010-09-20
这家伙很懒,什么也没写!
丢人了,没细看手册,不知道手册上有。。。
bernard
2010-09-21
这家伙很懒,什么也没写!
呵呵,哪里哪里 手册上说了些,很可能说得不够详细,所以如果能够自己再行分析一遍会加深印象很多很多
ysdaniel
2011-07-27
这家伙很懒,什么也没写!
学习了
撰写答案
登录
注册新账号
关注者
0
被浏览
6k
关于作者
rwen2012
这家伙很懒,什么也没写!
提问
1
回答
1
被采纳
0
关注TA
发私信
相关问题
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
开源共生 商业共赢 | RT-Thread 2024开发者大会议程正式发布!
2
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
3
RT-Thread EtherKit开源以太网硬件正式发布
4
如何在master上的BSP中添加配置yml文件
5
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
19
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
6
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
5
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部