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 */
}

 

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