RTX笔记14 - RTX5 osThreadNew 函数简单分析
1 /// Create a thread and add it to Active Threads. 2 osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) { 3 osThreadId_t thread_id; 4 5 EvrRtxThreadNew(func, argument, attr); 6 if (IsException() || IsIrqMasked()) { 7 EvrRtxThreadError(NULL, (int32_t)osErrorISR); 8 thread_id = NULL; 9 } else { 10 thread_id = __svcThreadNew(func, argument, attr); 11 } 12 return thread_id; 13 }
OSThreadNew函数原型如上所示。
EvrRtxThreadNew:事件记录器(Event Recorder)函数,只有在开启事件记录器的时候才有效。
IsException():检查是否处于异常处理程序中。如果是,则直接返回中断错误码。
IsIrqMasked():从优先级掩码寄存器primask返回优先级掩码位的当前状态。如果primask被设置为1,说明关闭了除 NMI 和硬 fault 之外的所有异常,则直接返回中断错误码。
__svcThreadNew:如果中断检测通过,则最终调用这个函数创建线程。该函数实现SVC系统调用,编号为0。该函数的具体定义如下:
1 SVC0_3 (ThreadNew, osThreadId_t, osThreadFunc_t, void *, const osThreadAttr_t *)
SVC0_3代表SVC0,系统调用的输入参数有三个。SVC0_3是一个宏定义函数,原型如下:
1 #define SVC0_3(f,t,t1,t2,t3) \ 2 __attribute__((always_inline)) \ 3 __STATIC_INLINE t __svc##f (t1 a1, t2 a2, t3 a3) { \ 4 SVC_ArgR(0,a1); \ 5 SVC_ArgR(1,a2); \ 6 SVC_ArgR(2,a3); \ 7 SVC_ArgF(svcRtx##f); \ 8 SVC_Call0(SVC_In3, SVC_Out1, SVC_CL0); \ 9 return (t) __r0; \ 10 }
1 #define SVC_RegF "r7" 2 3 #define SVC_ArgF(f) \ 4 register uint32_t __rf __ASM(SVC_RegF) = (uint32_t)f 5 6 #define SVC_ArgR(n,a) \ 7 register uint32_t __r##n __ASM("r"#n) = (uint32_t)a 8 9 #define SVC_Call0(in, out, cl) \ 10 __ASM volatile ("svc 0" : out : in : cl)
其中SVC_ArgR、SVC_ArgF、SVC_Call0也都是宏定义。将其分别代入之后,得到__svcThreadNew函数的具体实现:
1 __attribute__((always_inline)) \ 2 __STATIC_INLINE osThreadId_t __svcThreadNew (osThreadFunc_t a1, void * a2, const osThreadAttr_t * a3) { \ 3 register uint32_t __r0 __ASM("r0") = (uint32_t)a1 \ 4 register uint32_t __r1 __ASM("r1") = (uint32_t)a2 \ 5 register uint32_t __r2 __ASM("r2") = (uint32_t)a3 \ 6 register uint32_t __rf __ASM("r7") = (uint32_t)svcRtxThreadNew \ 7 __ASM volatile ("svc 0" : "=r"(__r0) : "r"(__rf),"r"(__r0),"r"(__r1),"r"(__r2) : ); \ 8 return (osThreadId_t) __r0; \ 9 }
可以看出__svcThreadNew函数触发SVC系统调用之后,最终调用了svcRtxThreadNew函数创建线程。
注:RTX5的很多API操作都是通过SVC0间接执行的。