RT_Thread Thread与scheduler

一、目的

     从阅读/分析代码的方式来了解RT_Thread 的线程与线程调用。

     为了方便描述,结构体或者代码有做精简(比如:拿掉了一些由宏开关控制使能的功能,一些函数入口检测等等),其与CPU架构相关的硬件底层函数以cortex-m3为例。

二、How

2.1 线程控制块定义  

      类似于其他的操作系统, 会定义一个诸如Task Control Block(TCB)的结构体来维护线程的属性与状态。RT_Thread 的TCB 如下所示,通过分析该struct,可以了解或者先行猜想各个元素的作用。

/**
 * Thread structure
 */
struct rt_thread
{
    /* rt object */
    char        name[RT_NAME_MAX];                      /**< the name of thread */
    rt_uint8_t  type;                                   /**< type of object */
    rt_uint8_t  flags;                                  /**< thread's flags */

    rt_list_t   list;                                   /**< the object list */
    rt_list_t   tlist;                                  /**< the thread list */

    /* stack point and entry */
    void       *sp;                                     /**< stack point */
    void       *entry;                                  /**< entry */
    void       *parameter;                              /**< parameter */
    void       *stack_addr;                             /**< stack address */
    rt_uint32_t stack_size;                             /**< stack size */

    /* error code */
    rt_err_t    error;                                  /**< error code */

    rt_uint8_t  stat;                                   /**< thread status */

    /* priority */
    rt_uint8_t  current_priority;                       /**< current priority */
    rt_uint8_t  init_priority;                          /**< initialized priority */
    rt_uint32_t number_mask;

    rt_ubase_t  init_tick;                              /**< thread's initialized tick */
    rt_ubase_t  remaining_tick;                         /**< remaining tick */

    struct rt_timer thread_timer;                       /**< built-in thread timer */

    void (*cleanup)(struct rt_thread *tid);             /**< cleanup function when thread exit */

    rt_uint32_t user_data;                             /**< private user data beyond this thread */
};

typedef struct rt_thread *rt_thread_t;

2.2 thread 的状态切换与各API

2.2.1 thread 状态与状态转移

参考官网wiki提供的thread 状态转移图,后面会以此图进行展开:

   thread 的状态记录在rt_thread_t 字段, 其定义如下:

#define RT_THREAD_INIT                  0x00                /**< Initialized status */
#define RT_THREAD_READY                 0x01                /**< Ready status */
#define RT_THREAD_SUSPEND               0x02                /**< Suspend status */
#define RT_THREAD_RUNNING               0x03                /**< Running status */
#define RT_THREAD_BLOCK                 RT_THREAD_SUSPEND   /**< Blocked status */
#define RT_THREAD_CLOSE                 0x04                /**< Closed status */
#define RT_THREAD_STAT_MASK             0x07

2.2.2 Thread 初始状态(RT_THREAD_INIT)

该状态由rt_thread_create/rt_thread_init 进入, 其中rt_thread_create与rt_thread_init相比,主要多了动态申请Thread结构资源的部分,其核心部分都调用_rt_thread_init 函数,如下:

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)
{
    /* init thread list */
    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,
                                          (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
                                          (void *)rt_thread_exit);     【1】

    /* priority init */
    RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
    thread->init_priority    = priority;
    thread->current_priority = priority;

    thread->number_mask = 0;

    /* tick init */
    thread->init_tick      = tick;
    thread->remaining_tick = tick;

    /* error and flags */
    thread->error = RT_EOK;
    thread->stat  = RT_THREAD_INIT;

    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    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);      【2】

    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));

    return RT_EOK;
}

【1】rt_hw_stack_init 会根据不同的CPU架构来构造不同的栈帧设置一个初始上下文环境,比如针对cortex-m3,

/*File: libcpu/arm/cortex-m3/cpuport.c*/

/**
 * This function will initialize thread stack
 *
 * @param tentry the entry of thread
 * @param parameter the parameter of entry
 * @param stack_addr the beginning stack address
 * @param texit the function will be called when thread exit
 *
 * @return stack address
 */
rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
                             rt_uint8_t *stack_addr,
                             void       *texit)
{
    struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    unsigned long       i;

    stk  = stack_addr + sizeof(rt_uint32_t);
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
    stk -= sizeof(struct stack_frame);

    stack_frame = (struct stack_frame *)stk;

    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }

    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; /* r0 : argument */
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    stack_frame->exception_stack_frame.r12 = 0;                        /* r12 */
    stack_frame->exception_stack_frame.lr  = (unsigned long)texit;     /* lr */
    stack_frame->exception_stack_frame.pc  = (unsigned long)tentry;    /* entry point, pc */
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR */

    /* return task's current stack address */
    return stk;
}

其栈帧结构体和图示如下所示,注意栈是向下生长:

struct exception_stack_frame
{
    rt_uint32_t r0;
    rt_uint32_t r1;
    rt_uint32_t r2;
    rt_uint32_t r3;
    rt_uint32_t r12;
    rt_uint32_t lr;
    rt_uint32_t pc;
    rt_uint32_t psr;
};

struct stack_frame
{
    /* r4 ~ r11 register */
    rt_uint32_t r4;
    rt_uint32_t r5;
    rt_uint32_t r6;
    rt_uint32_t r7;
    rt_uint32_t r8;
    rt_uint32_t r9;
    rt_uint32_t r10;
    rt_uint32_t r11;

    struct exception_stack_frame exception_stack_frame;
};

【2】因为线程同步等API 有时会依赖于time out 功能,所以在这边初始化了一个timer定时器,它的功能是在定时时间到后回调rt_thread_timeout 函数,该函数会将被suspend的thread 重新放入ready 列表。之后我们会再次回到这个函数。

2.2.3 线程就绪状态(RT_THREAD_READY)

对于一个由2.2.1 新建的thread, 通过调用rt_thread_startup使线程进入ready状态。而对于其他被suspend的线程,其回到就绪状态也同样会调用rt_thread_resume。

/**
 * This function will start a thread and put it to system ready queue
 *
 * @param thread the thread to be started
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_startup(rt_thread_t thread)
{
    /* set current priority to init priority */
    thread->current_priority = thread->init_priority;

    /* calculate priority attribute */
    thread->number_mask = 1L << thread->current_priority;

    /* change thread stat */
    thread->stat = RT_THREAD_SUSPEND;
    /* then resume it */
    rt_thread_resume(thread);       
    if (rt_thread_self() != RT_NULL)
    {
        /* do a scheduling */
        rt_schedule();
    }

    return RT_EOK;
}

所以我们先看下rt_thread_resume做了什么。可以看到,其首先检查传入的thread是否处于suspend 状态(因为这个原因,上面的startup函数会首先设置thread 为suspend状态)),其次会将thread从suspend list 中移除并插入到ready list。 从这边可以看到,内核对线程的管理主要维护了两张list——suspend list和ready lists(为什么是带复数的liists,见下面的rt_schedule_insert_thread函数)。

/**
 * This function will resume a thread and put it to system ready queue.
 *
 * @param thread the thread to be resumed
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_resume(rt_thread_t thread)
{
    register rt_base_t temp;

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
    {
        return -RT_ERROR;
    }

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));

    rt_timer_stop(&thread->thread_timer);

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);  

    return RT_EOK;
}

rt_thread_resume中会调用rt_schedule_insert_thread:

void rt_schedule_insert_thread(struct rt_thread *thread)
{
    register rt_base_t temp;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* it's current thread, it should be RUNNING thread */
    if (thread == rt_current_thread)   【1】
    {
        thread->stat = RT_THREAD_RUNNING | (thread->stat & ~RT_THREAD_STAT_MASK);
        goto __exit;
    }

    /* READY thread, insert to ready queue */
    thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
    /* insert thread to ready list */  
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                          &(thread->tlist));  【2】


    /* set priority mask */
    rt_thread_ready_priority_group |= thread->number_mask; 【3】

__exit:
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
}

【1】:如果当前待插入ready list 的thread 正好是处于running状态的thread,则直接退出;

【2】插入对应优先级的read list,

【3】将rt_thread_ready_priority_group中与优先级对应的field bit 置一,后面说明为什么需要这步动作。

好了,回到该小节最开始的rt_thread_startup函数,当将对应的thread resume之后,ready list 已有更新,我们需要重新调度调度器来选择合适的thread。

2.2.3 运行状态[RT_THREAD_RUNNING]

对于已提交到ready lists的新建thread 或者resume 回来的被阻塞的thread, 内核会根据thread的优先级选择thread。这主要由re_schedule来实现, 这也是调度器的核心函数。

/**
 * 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)
    {
        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;

            to_thread = _get_highest_priority_thread(&highest_ready_priority);  【1】

            if ((rt_current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)【2】
            {
                if (rt_current_thread->current_priority < highest_ready_priority)
                {
                    to_thread = rt_current_thread;
                }
                else if (rt_current_thread->current_priority == highest_ready_priority && (rt_current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
                {
                    to_thread = rt_current_thread;
                }
                else
                {
                    rt_current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
                    need_insert_from_thread = 1;
                }
            }

            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;

                if (need_insert_from_thread) 【3】
                {
                    rt_schedule_insert_thread(from_thread);
                }

                rt_schedule_remove_thread(to_thread);
                to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);

                /* switch to new thread */
                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); 【4】

                    /* enable interrupt */
                    rt_hw_interrupt_enable(level);

                    goto __exit;
                }
                else
                {
                    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));
                    rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,
                            (rt_ubase_t)&to_thread->sp); 【5】
                }
            }
            else
            {
                rt_schedule_remove_thread(rt_current_thread); 【6】
                rt_current_thread->stat = RT_THREAD_RUNNING | (rt_current_thread->stat & ~RT_THREAD_STAT_MASK);
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

__exit:
    return;
}

【1】:_get_highest_priority_thread,该函数无论对于何种优先级的thread,都会在定长的常数时间内获得当前系统的最高优先级的thread,该概念有点类似ucOSII 中的task group table。

其核心思想是对于插入的每一个thread, 会根据优先级设置rt_thread_ready_priority_group 对应的bit位,而每一个bit会对应一个thread list。[插图]

/**
 * This function finds the first bit set (beginning with the least significant bit)
 * in value and return the index of that bit.
 *
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
 * zero from any of these functions means that the argument was zero.
 *
 * @return return the index of the first bit set. If value is 0, then this function
 * shall return 0.
 */
int __rt_ffs(int value)
{
    if (value == 0) return 0;

    if (value & 0xff)
        return __lowest_bit_bitmap[value & 0xff] + 1;

    if (value & 0xff00)
        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;

    if (value & 0xff0000)
        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;

    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}

static struct rt_thread* _get_highest_priority_thread(rt_ubase_t *highest_prio)
{
    register struct rt_thread *highest_priority_thread;
    register rt_ubase_t highest_ready_priority;

    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;

    /* get highest ready priority thread */
    highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    *highest_prio = highest_ready_priority;

    return highest_priority_thread;
}

【2】如果内核当前的rt_current_thread 处于running状态,即当前有thread 在run, 那么比较rt_current_thread和highest_ready_priority的优先级,分三种情况进行处理:

(1)rt_current_thread 的优先级最高,则维持当前thread;

(2)rt_current_thread和highest_ready_priority优先级相同,且时间片还没有用完(后续涉及),则维持当前thread;

(3)除去上面的两种情况,说明需要hread上下文切换

【3】在上诉【2】中第二种情况下,需要将current thread 重新插入ready队列,因为它是因为时间片用完才让出CPU的,而不是在等待某些外部lock等等。这种情况产生条件可以看下rt_tick_increase这个function,该function会在每个TICK ISR中调用,每流逝一个tick, 当前正在运行thread 的remaining tick 会减去1个tick,等到tick 清零后,会设置RT_THREAD_STAT_YIELD flag,然后重新调用调度器。

/**
 * This function will let current thread yield processor, and scheduler will
 * choose a highest thread to run. After yield processor, the current thread
 * is still in READY state.
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_yield(void)
{
    rt_schedule();

    return RT_EOK;
}

/**
 * This function will notify kernel there is one tick passed. Normally,
 * this function is invoked by clock ISR.
 */
void rt_tick_increase(void)
{
    struct rt_thread *thread;

    /* increase the global tick */
    ++ rt_tick;

    /* check time slice */
    thread = rt_thread_self();

    -- thread->remaining_tick;
    if (thread->remaining_tick == 0)
    {
        /* change to initialized tick */
        thread->remaining_tick = thread->init_tick;

        thread->stat |= RT_THREAD_STAT_YIELD;

        /* yield */
        rt_thread_yield();
    }

    /* check timer */
    rt_timer_check();
}

【4】【5】根据当前是否处于中断,调用不同的上下文切换函数,见我的另一篇文章。

【6】将current thread 从ready list 移除,因为它已处于running 状态。其函数与rt_schedule_insert_thread执行相反的操作,暂时还没厘清在什么情况下会进入这个分支。而且存在冗余操作,比如current thread的优先级比其他的thread 的优先级都高,即不用切换上下文,这时候to_thread == rt_current_thread,但仍然要执行rt_schedule_remove_thread的逻辑。

void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
    {
        rt_thread_ready_priority_group &= ~thread->number_mask;
    }

2.2.4 线程挂起状态[RT_THREAD_BLOCK]
首先来看 rt_thread_suspend

/**
 * This function will suspend the specified thread.
 *
 * @param thread the thread to be suspended
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 *
 * @note if suspend self thread, after this function call, the
 * rt_schedule() must be invoked.  【1】
 */
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
    register rt_base_t stat;
    register rt_base_t temp;

    stat = thread->stat & RT_THREAD_STAT_MASK;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
    if (stat == RT_THREAD_RUNNING)  
    {
        /* not suspend running status thread on other core */
        RT_ASSERT(thread == rt_thread_self());  【2】
    }

    /* change thread stat */
    rt_schedule_remove_thread(thread);
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);

    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer)); 【3】

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    return RT_EOK;
}

【1】官方文档有说明说:通常不应该使用这个函数来挂起线程本身,如果确实需要采用 rt_thread_suspend() 函数挂起当前任务,需要在调用 rt_thread_suspend() 函数后立刻调用 rt_schedule() 函数进行手动的线程上下文切换。用户只需要了解该接口的作用,不推荐使用该接口。

【2】线程只能suspend自己。

【3】无论当前thread 的timer处于何种状态,stop any way

那接下来的问题是,谁会调用rt_thread_suspend呢?

这里有些例子:

(1)rt_thread_sleep:还记得在thread init 的时候有init 一个timer 定时器吗,这边就利用了这个定时器来重设定时时间并开始计时。

/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_sleep(rt_tick_t tick)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* set to current thread */
    thread = rt_thread_self();
   
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* suspend thread */
    rt_thread_suspend(thread);

    /* reset the timeout of thread timer and start it */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
    rt_timer_start(&(thread->thread_timer));

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    rt_schedule();

    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;

    return RT_EOK;
}

等到定时时间到后,其会调用注册的rt_thread_timeout函数,该函数会将time out的thread重新加入到read list,从而该线程有继续往下运行的机会。

/**
 * This function is the timeout function for thread, normally which is invoked
 * when thread is timeout to wait some resource.
 *
 * @param parameter the parameter of thread timeout function
 */
void rt_thread_timeout(void *parameter)
{
    struct rt_thread *thread;

    thread = (struct rt_thread *)parameter;

    /* set error number */
    thread->error = -RT_ETIMEOUT;

    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));

    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);

    /* do schedule */
    rt_schedule();
}

(2) rt_sem_take(rt_sem_t sem, rt_int32_t time)等多种线程中同步与通信接口中, 打算放在下一回的分析中。

2.2.5 关闭状态[RT_THREAD_CLOSE]

还记得在rt_thread_init中在构造栈帧的时候对LR(返回地址)有赋值为rt_thread_exit吗? 该函数会在thread 运行退出后运行,

oid rt_thread_exit(void)
{
    struct rt_thread *thread;
    register rt_base_t level;

    /* get current thread */
    thread = rt_thread_self();

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /* remove from schedule */
    rt_schedule_remove_thread(thread);
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

    /* remove it from timer list */
    rt_timer_detach(&thread->thread_timer);

    if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
        thread->cleanup == RT_NULL)
    {
        rt_object_detach((rt_object_t)thread); 
    }
    else
    {
        /* insert to defunct thread list */
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); 【1】
    }

    /* switch to next task */
    rt_schedule();

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}

【1】rt_thread_exit会将当前的thread 插入rt_thread_defunct list,等待idle thread 执行后续的清理工作,见下面的代码

/**
 * @ingroup Thread
 *
 * This function will perform system background job when system idle.
 */
void rt_thread_idle_excute(void)
{
    /* Loop until there is no dead thread. So one call to rt_thread_idle_excute
     * will do all the cleanups. */
    while (_has_defunct_thread())
    {
        rt_base_t lock;
        rt_thread_t thread;

        RT_DEBUG_NOT_IN_INTERRUPT;

        /* disable interrupt */
        lock = rt_hw_interrupt_disable();

        /* re-check whether list is empty */
        if (_has_defunct_thread())
        {
            /* get defunct thread */
            thread = rt_list_entry(rt_thread_defunct.next,
                                   struct rt_thread,
                                   tlist);

            /* remove defunct thread */
            rt_list_remove(&(thread->tlist));

            /* lock scheduler to prevent scheduling in cleanup function. */
            rt_enter_critical(); 【1】

            /* invoke thread cleanup */
            if (thread->cleanup != RT_NULL)
                thread->cleanup(thread);  【2】

            /* if it's a system object, not delete it */

            /* unlock scheduler */
            rt_exit_critical();
        }
        else
        {
            /* enable interrupt */
            rt_hw_interrupt_enable(lock);

            /* may the defunct thread list is removed by others, just return */
            return;
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(lock);

#ifdef RT_USING_HEAP 【3】
        /* release thread's stack */
        RT_KERNEL_FREE(thread->stack_addr);   
        /* delete thread object */
        rt_object_delete((rt_object_t)thread); 
#endif
    }
}

【1】这边的调用可能没有意义,因为全局中断已被关闭了

【2】执行thread 本省的clean up动作,比如malloc 的资源

【3】释放栈空间,释放动态create的thread 结构体空间

2.3 系统Thread

2.3.1 空闲线程

其实在2.2.5 中我们已经看到过空闲线程的功能的一部分,即清理thread 环境来释放资源。

/*File: idle.c*/

extern void rt_system_power_manager(void);
static void rt_thread_idle_entry(void *parameter)
{

    while (1)
    { 
#ifdef RT_USING_IDLE_HOOK 【1】
        rt_size_t i;

        for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
        {
            if (idle_hook_list[i] != RT_NULL)
            {
                idle_hook_list[i]();
            }
        }
#endif

        rt_thread_idle_excute(); 【2】
#ifdef RT_USING_PM        
        rt_system_power_manager(); 【3】
#endif
    }
}

【1】:执行hook 钩子函数,钩子函数的设置/删除API为rt_thread_idle_sethook/rt_thread_idle_delhook

【2】:这个之前已涉及到;

【3】可选的power manager 控制调用入口

2.3.2 主线程

/* the system main thread */
void main_thread_entry(void *parameter)
{
    extern int main(void);
    
    /* invoke system main function */
    main();
}

void rt_application_init(void)
{
    rt_thread_t tid;

    rt_err_t result;

    tid = &main_thread;
    result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
                            main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
    RT_ASSERT(result == RT_EOK);

    /* if not define RT_USING_HEAP, using to eliminate the warning */
    (void)result;

    rt_thread_startup(tid);
}

2.3.3整个系统thread的启动

/*File: components.c*/
int rtthread_startup(void)
{
    rt_hw_interrupt_disable();

    /* board level initialization
     * NOTE: please initialize heap inside board initialization.
     */
    rt_hw_board_init();

    /* show RT-Thread version */
    rt_show_version();

    /* timer system initialization */
    rt_system_timer_init();

    /* scheduler system initialization */
    rt_system_scheduler_init();   【1】

#ifdef RT_USING_SIGNALS
    /* signal system initialization */
    rt_system_signal_init();
#endif

    /* create init_thread */
    rt_application_init();  【2】

    /* timer thread initialization */
    rt_system_timer_thread_init(); 【3】

    /* idle thread initialization */
    rt_thread_idle_init();  【4】

    /* start scheduler */
    rt_system_scheduler_start(); 【5】

    /* never reach here */
    return 0;
}

【1】初始化一些后续会用到的thread list 和相关的全局变量,比如 rt_thread_priority_table、thread defunct list

【2】初始化主线程

【3】初始化timer 线程,该thread 主要支持soft timer (软定时器)的处理

【4】初始化idle线程

【5】开启调度器,它会选择当前系统中最高优先级的thread,然后调用rt_hw_context_switch_to来运行该线程。


/**
 * @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;
    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;

    /* switch to new thread */
    rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp);

    /* never come back */
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章