闲来无事,作为第一次使用实时操作系统的小白想看看rtthread的调度方式。
总结:
主要调度使用scheduler.c和context——gcc.s。
void rt_system_scheduler_start(void)
{
register struct rt_thread *to_thread;
rt_ubase_t highest_ready_priority;
to_thread = _get_highest_priority_thread(&highest_ready_priority);
rt_current_thread = to_thread;
rt_schedule_remove_thread(to_thread);
to_thread->stat = rt_thread_running;
rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp);//跳转至.s文件执行
}
第一次会调用此函数用来执行一个.s文件
c
rt_hw_context_switch_to:
ldr r1, =rt_interrupt_to_thread
str r0, [r1] / 将rt_interrupt_to_thread写入一个sp指针待会会用到 /
/* set interrupt flag to 1 /
ldr r1, =rt_thread_switch_interrupt_flag
mov r0, #1
str r0, [r1]
...
ldr r0, =nvic_int_ctrl / trigger the pendsv exception (causes context switch) /
ldr r1, =nvic_pendsvset
str r1, [r0] / nvic_int_ctrl为icsr寄存器将28位置1会导致一个sv异常,任务切 换也在sv中进行 /
/ restore msp */
ldr r0, =scb_vtor / vtor保存着内存地址偏移,取出偏移值赋值给msp寄存器 /
ldr r0, [r0]
ldr r0, [r0]
nop
msr msp, r0
...
第一次触发的sv异常
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 / 获取需要切换的任务的sp指针 /
ldr r1, [r1]
ldr r1, [r1] / load thread stack pointer /
ldmfd r1!, {r4 - r11} / pop r4 - r11 register /
msr psp, r1 / update stack pointer /
/ 此时psp寄存器已指向我们目标任务的sp /
pendsv_exit:
/ restore interrupt */
msr primask, r2
orr lr, lr, #0x04
bx lr
在后续的轮转中我们会调用
void rt_schedule(void)
{
rt_base_t level;
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)
{
rt_ubase_t highest_ready_priority;
if (rt_thread_ready_priority_group != 0)
{
/ need_insert_from_thread: need to insert from_thread to ready queue /
int need_insert_from_thread = 0;
/ 获取任务列表中优先级最高的我们假设有比当前任务更高的优先级执行39行,此时目标任务为高优先级任务 /
to_thread = _get_highest_priority_thread(&highest_ready_priority);
...
if (to_thread != rt_current_thread)
{
/ if the destination thread is not the same as current thread /
/ 开始进行转换,首先将源任务设置为当前任务,再将当前任务设置为目标任务 /
rt_current_priority = (rt_uint8_t)highest_ready_priority;
from_thread = rt_current_thread;
rt_current_thread = to_thread;
...
#ifdef rt_using_overflow_check
_rt_scheduler_stack_check(to_thread);
#endif
if (rt_interrupt_nest == 0)
{
extern void rt_thread_handle_sig(rt_bool_t clean_state);
/ 这句进行任务切换 /
rt_hw_context_switch((rt_ubase_t)&from_thread->sp,
(rt_ubase_t)&to_thread->sp);
/ enable interrupt /
rt_hw_interrupt_enable(level);
goto __exit;
}
else
{
rt_debug_log(rt_debug_scheduler, (switch in interruptn));
rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,
(rt_ubase_t)&to_thread->sp);
}
}
else
{
rt_schedule_remove_thread(rt_current_thread);
rt_current_thread->stat = rt_thread_running | (rt_current_thread->stat & ~rt_thread_stat_mask);
}
}
}
/ enable interrupt /
rt_hw_interrupt_enable(level);
__exit:
return;
}
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
/ 没有设置interrupt_flag跳过执行 /
beq _reswitch
/ 再次置1用于sv异常 /
mov r3, #1
str r3, [r2]
/ 将源任务sp赋值给rt_interrupt_from_thread,此时from是有值的 /
ldr r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread /
str r0, [r2]
_reswitch:
/ 将目标任务sp赋值给rt_interrupt_to_thread*/
ldr r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread /
str r1, [r2]
/ 再次进入sv异常处理 /
ldr r0, =nvic_int_ctrl / trigger the pendsv exception (causes context switch) */
ldr r1, =nvic_pendsvset
str r1, [r0]
bx lr
此时sv处理与上次相比多了一个源任务的r4-r11的压栈处理其他相同。
高通宣布成为2021PEL和平精英职业联赛官方战略合作伙伴
SiC和GaN系统设计工程师不再迷茫
OI1842函数信号发生器的技术指标i推动分析
Debian终于完全删除Python 2
如何使用高光谱成像技术进行作物健康监测?
从裸机到rtt任务切换有感
SIMATIC S7-1500 PLC GRAPH编程教程
53181A频率计数器说明资料
浅谈SOA架构下的OTA解决方案
详细解析芯片里的众多晶体管是如何实现的
半导体制冷技术应用--肿瘤免疫化学发光检测仪
万元超轻佳能全画幅微单EOS RP 性价比超高
VCM音圈马达的激光焊锡工艺应用
RF电路中的VSWR测试和保护设计的解决方案
天耀宏图与欧拉社区共同打造安全创新、兼容稳定的云应用
最新的上行通道射频放大器ARA2021
简述电磁兼容三要素
chatgpt哪个公司做的
可以直接用直流电给蓄电池进行充电吗
fpga的开发流程有哪些步骤?fpga和嵌入式系统的区别在哪里?