一、目的
從閱讀/分析代碼的方式來了解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 */
}