rt-thread线程调度器源码分析

1 前言

RT-Thread中提供的线程调度器是基于全抢占式优先级的调度,在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身.系统总共支持256个优先级(0 ~ 255,数值越小的优先级越高,0为最高优先级,255分配给空闲线程使用,一般用户不使用。在一些资源比较紧张的系统中,可以根据情况选择只支持8个或32个优先级的系统配置)。在系统中,当有比当前线程优先级还要高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理机进行执行。

2 线程优先级管理系统

rt-thread采用一个数组来实现线程优先级管理系统,如下图所示,RT-Thread调度器实现中包含一组,总共256个优先级队列数组(如果系统最大支持32个优先级,那么这里将是32个优先级队列数组),每个优先级队列采用双向环形链表的方式链接,255优先级队列中一般只包含一个idle线程。

rt-thread线程调度器源码分析_第1张图片

其源码定义如下:

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

2 调度器初始化

/**
 * @ingroup SystemInit
 * This function will initialize the system scheduler
 */
void rt_system_scheduler_init(void)
{
    register rt_base_t offset;

    rt_scheduler_lock_nest = 0;//调度器嵌套锁计数器设为0

    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",
                                      RT_THREAD_PRIORITY_MAX));

    for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)//所有优先级对应的线程链表初始化
    {
        rt_list_init(&rt_thread_priority_table[offset]);
    }

    rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;//rt_current_prority为全局变量,初始化
    rt_current_thread = RT_NULL;//全局变量rt_current_thread初始化为空

    /* initialize ready priority group */
    rt_thread_ready_priority_group = 0;//全局变量rt_thread_ready_priority_group初始化为0

#if RT_THREAD_PRIORITY_MAX > 32
    /* initialize ready table */
    rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));
#endif

    /* initialize thread defunct */
    rt_list_init(&rt_thread_defunct);//初始化全局空闲线程处理的回调线程链表,rt_thread_defunct为这线程链表,只在系统空闲时被空闲线程操作
}

3 启动线程调度器

/**
 * @ingroup SystemInit
 * This function will startup scheduler. It will select one thread
 * with the highest priority level, then switch to it.
 */
void rt_system_scheduler_start(void)
{
    register struct rt_thread *to_thread;
    register rt_ubase_t highest_ready_priority;
    //以下代码是查找出新高优先级的线程
#if RT_THREAD_PRIORITY_MAX == 8
    highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];
#else
    register rt_ubase_t number;
    /* 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
#endif

    /* get switch to thread *///得到线程
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    rt_current_thread = to_thread;//设置当前线程

    /* switch to new thread */
    rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);//此函数是与MCU相关的函数,实现切换到目的线程的功能

    /* never come back */
}


4 往调度器添加线程

/*
 * This function will insert a thread to system ready queue. The state of
 * thread will be set as READY and remove from suspend queue.
 *
 * @param thread the thread to be inserted
 * @note Please do not invoke this function in user application.
 */
void rt_schedule_insert_thread(struct rt_thread *thread)
{
    register rt_base_t temp;

    RT_ASSERT(thread != RT_NULL);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//关中断

    /* change stat */
    thread->stat = RT_THREAD_READY;

    /* insert thread to ready list */
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),//往当前优先级链表中添加线程节点
                          &(thread->tlist));

    /* set priority mask */
#if RT_THREAD_PRIORITY_MAX <= 32
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%s], the priority: %d\n", 
                                      thread->name, thread->current_priority));
#else
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                 ("insert thread[%s], the priority: %d 0x%x %d\n", 
                  thread->name,
                  thread->number,
                  thread->number_mask,
                  thread->high_mask));
#endif

#if RT_THREAD_PRIORITY_MAX > 32
    rt_thread_ready_table[thread->number] |= thread->high_mask;
#endif
    rt_thread_ready_priority_group |= thread->number_mask;

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断
}

5 将线程从调度器中移除

/*
 * This function will remove a thread from system ready queue.
 *
 * @param thread the thread to be removed
 *
 * @note Please do not invoke this function in user application.
 */
void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t temp;

    RT_ASSERT(thread != RT_NULL);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//关中断

#if RT_THREAD_PRIORITY_MAX <= 32
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%s], the priority: %d\n", 
                                      thread->name, thread->current_priority));
#else
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                 ("remove thread[%s], the priority: %d 0x%x %d\n", 
                  thread->name,
                  thread->number,
                  thread->number_mask,
                  thread->high_mask));
#endif

    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));//从队列中移除
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))//如果当前优先级链表已空
    {
#if RT_THREAD_PRIORITY_MAX > 32
        rt_thread_ready_table[thread->number] &= ~thread->high_mask;
        if (rt_thread_ready_table[thread->number] == 0)
        {
            rt_thread_ready_priority_group &= ~thread->number_mask;
        }
#else
        rt_thread_ready_priority_group &= ~thread->number_mask;
#endif
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断
}

6 线程调度

/**
 * @addtogroup Thread
 */

/*@{*/

/**
 * This function will perform one schedule. It will select one thread
 * with the highest priority level, then switch to it.
 */
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)//当前不处于线程嵌套中
    {
        register rt_ubase_t highest_ready_priority;
        //以下代码是获取当前最高优先级的线程的优先级
#if RT_THREAD_PRIORITY_MAX == 8
        highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];
#else
        register rt_ubase_t number;
        /* 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
#endif
        /* 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 = (rt_uint8_t)highest_ready_priority;//更新一些变量
            from_thread         = rt_current_thread;
            rt_current_thread   = to_thread;

            RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));

            /* switch to new thread */
            RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                         ("[%d]switch to priority#%d thread:%s\n",
                          rt_interrupt_nest,
                          highest_ready_priority,
                          to_thread->name));

#ifdef RT_USING_OVERFLOW_CHECK
            _rt_scheduler_stack_check(to_thread);//线程栈溢出检查
#endif

            if (rt_interrupt_nest == 0)//如果当前没有处于中断嵌套中
            {
                rt_hw_context_switch((rt_uint32_t)&from_thread->sp,//线程切换,此函数为MCU相关函数,与具体使用的MCU相关,这里不作介绍
                                     (rt_uint32_t)&to_thread->sp);
            }
            else//如果当前处于中断例程中
            {
                RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));

                rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,//线程切换,与rt_hw_context_switch类似
                                               (rt_uint32_t)&to_thread->sp);
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);//开中断
}

7 进入临界区

此函数实现上实现的是禁止调度,也就是说,执行了此函数,调度器将不再调度线程,这个从第6章的语句if (rt_scheduler_lock_nest == 0) ...可以看出来。

/**
 * This function will lock the thread scheduler.
 */
void rt_enter_critical(void)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();//关中断

    /*
     * the maximal number of nest is RT_UINT16_MAX, which is big
     * enough and does not check here
     */
    rt_scheduler_lock_nest ++;//调度锁计数器加1

    /* enable interrupt */
    rt_hw_interrupt_enable(level);//开中断
}

8 退出临界区

与进入临界区对应,此函数实现的是让之前禁止的调度器重新调度线程,其源码如下所示:

/**
 * This function will unlock the thread scheduler.
 */
void rt_exit_critical(void)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();//关中断

    rt_scheduler_lock_nest --;//调度锁嵌套计数器减1

    if (rt_scheduler_lock_nest <= 0)//如果调度锁嵌套计数器小于或等于0,则置其为0
    {
        rt_scheduler_lock_nest = 0;
        /* enable interrupt */
        rt_hw_interrupt_enable(level);//开中断

        rt_schedule();//调度线程
    }
    else
    {
        /* enable interrupt */
        rt_hw_interrupt_enable(level);//开中断
    }
}


前面源码中的调度器启动rt_system_scheduler_start和调度rt_schedule的对应源码中都有使用位图来实现获取当前最高优先级线程对应的优先缓的算法,就不在这里做详细介绍,下一章将专门来讨论此算法,敬请关注.


你可能感兴趣的:(rt-thread线程调度器源码分析)