嵌入式技术论坛
直播中

郑成枝

8年用户 1385经验值
私信 关注
[经验]

第一次使用实时操作系统的小白想看看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的压栈处理其他相同。



原作者:陈再松

更多回帖

发帖
×
20
完善资料,
赚取积分