37、【OS】【Nuttx】OSTest分析(2):任务创建
背景
之前 wiki
22、【OS】【Nuttx】最小系统初始化分析(1):任务创建
简单分析了任务创建时的堆栈分配,这里对任务创建过程做进一步分析
tcb_s,task_tcb_s 和 pthread_tcb_s
来看下任务控制块的两种形式:tcb_s,task_tcb_s,pthread_tcb_s:
-
tcb_s:所有任务和线程公共的部分,每个任务或线程的 tcb 都包含这些公共定义,是任务控制逻辑的核心
-
task_tcb_s:是 tcb 的一种特殊形式,主要是为了扩展 tcb_s,专门用于任务(以及内核线程),不仅包含了所有 tcb_s 中的字段,还添加了额外的字段来满足任务特有的需求。
-
pthread_tcb_s:tcb 的另一种特殊形式,专门用于线程管理,与 task_tcb_s 区别开来,以节约内存消耗。
主要区别如下:
1、 pthread_tcb_s:one for pthreads,为线程提供控制模块功能;task_tcb_s:one for tasks,为任务提供控制模块功能。线程意味着没有自己独立的用户空间,较多的是通过指针来引用别人用户空间里面的内容;而任务意味着可以拥有自己的用户空间,可以提供内容给线程进行引用。
2、 tcb_s 是 task_tcb_s 和 pthread_tcb_s 的必要不充分条件,即 task_tcb_s 和 pthread_tcb_s 的成员必包含 tcb_s,但还有其他成员,所以 tcb_s 是不充分条件。注意,tcb_s 成员位于 task_tcb_s 和 pthread_tcb_s 中的 top 第一个位置,意味着线程用户通过 tcb_s* 指针可以直接取到 task_tcb_s 里面公共部分的内容。
3、group 成员在 tcb_s 中为指针,在 task_tcb_s 中为实例。tcb_s 中的指针用于指示该线程所属的任务组。通过这种方式,多个线程可以通过指向同一个 task_group_s 实例来共享资源或状态信息,这也是描述中所提到的,可以减少内存占用,线程不必拥有自己的数据副本,通过指针引用到任务的 task_group_s 共享资源即可。
task & kernel
下面来看 task 和 kernel 两种类型的任务创建
首先是关键公共函数 nxthread_create,该接口用于创建并激活一种特定类型的新线程(这里可以把任务也视为一种包含用户空间的特殊线程),并返回激活的线程 ID
线程类型如下:用户任务,用户线程,内核线程
查看 nxthread_create 调用点,只有用户任务和内核线程的创建,用户线程通过 nx_pthread_create 创建
用户通过 task_create 和 kthread_create 来控制新线程的创建
使用 nxthread_create 创建新线程,任务用户与内核用户的区别在于,是否需要使用 task_tcb_s 额外申请 group 实例,group 实例占用内存空间;内核用户不需要申请 group 实例,只需申请公共部分 tcb_s,group* 指针将引用 g_kthread_group 实例。
nxthread_create
这里主要做三个工作:
- 申请线程空间:包括 tcb 空间与 stack 空间
- 初始化 group 资源
- 初始化任务控制块 tcb,并根据任务状态,将任务添加到指定 schedule 队列(如 Ready,Blocked)以激活任务
1、 为 tcb 申请空间
2、 若 nxtask_init 初始化失败,释放之前申请的 tcb 空间
3、 描述主要说明 nxtask_init 和 task_create 区别,nxtask_init 负责执行 task_create 里面的子集,task_create 主要负责申请 tcb 空间,stack 可以通过 pre-allocated 传递进来(如果有的话,nxtask_init 不必再分配),激活 task。
4、初始化 group 资源,对于用户任务,已经在 task_tcb_s 中有 group 实例(即为 tcb 申请空间时,也间接申请了 group 空间);对于内核线程,使用 g_kthread_group 实例进行初始化,故 nxtask_init 这里没有 group 空间申请,只需进行初始化
5、若 task_create 没有预先分配 stack(由用户指定具体的栈空间),则由 Nuttx 使用 up_create_stack 进行分配;若用户指定了具体的栈空间,则 up_use_stack 直接使用;绑定了具体的 stack 空间后,进行 thread local storage 初始化,详情可查看之前 wiki 22、【OS】【Nuttx】最小系统初始化分析(1):任务创建 中关于 thread local storage 的描述,大致意思就是 stack 空间前面十几个字节需要存放该线程 stack 相关的信息。
6、前面 group 初始化,stack 空间申请,stack 初始化没啥毛病之后,开始初始化 tcb,并做一些 group 的后处理动作,主要是添加 group 识别信息,告诉该 group 的其他线程,该线程已经准备完毕,防止该线程前面有步骤初始化失败后被清理,group 中又添加了该线程的信息,其他任务后续会误识别该失败线程的信息。
7、nxtask_activate 激活任务,查看该任务是否需要执行,不需要就按指定 schedule 策略进行调度执行