一、目的
从阅读/分析代码的方式来了解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 */
}