文章目录
SYS/BIOS任务对象是由任务模块管理的线程。任务的优先级高于空闲循环,而优先级低于硬件和软件中断。
任务模块是根据任务的优先级和任务的当前执行状态动态地调度和抢占任务。这样可以确保处理器始终被分配给准备运行地最高优先级线程,有多达32个优先级可用于任务,默认级别数为16。最低优先级(0)是为运行空闲循环而保留的。
任务模块提供一组操作任务对象的函数。他们通过Task_Handle类型的句柄访问任务对象。
内核为每个任务对象维护一个处理器寄存器的副本。每个任务都有自己的运行时堆栈,用于存储本地变量以及进一步嵌套函数调用。
在单个程序中执行的所有任务都共享一组通用的全局变量,这些变量是根据为C函数定义的标准范围规则访问的。
Creating Tasks
创建任务可以动态的通过调用Task_create()函数创建,也可以在配置文件中静态的配置。动态创建的任务可以在程序执行期间被删除。
Creating and Deleting Tasks Dynamically
可以通过调用函数Task_create()生成SYS/BIOS任务,该函数的参数包括开始执行新任务的C函数的地址。
Task_create()返回值是Task_Handle类型的句柄,然后可以将其作为参数传递给其他任务函数。
任务在创建时变为活动状态,如果当前运行的任务具有更高的优先级,则会抢占该任务。
任务对象和堆栈使用的内存可以通过调用Task_delete()来回收。Task_delete()从所有内部队列中删除任务,并释放任务对象和堆栈。
任务持有的任何信号量或其他资源都不会被释放。删除包含此类资源的任务通常是程序设计错误。在大多数情况下,应该在删除任务之前释放这些资源。只有删除处于终止或非活动状态的任务才是安全的。
Creating Tasks Statically
静态创建任务可以在脚本中设置,配置允许为每个任务和任务管理器本身设置许多属性。
在运行时,静态创建的任务的行为与使用task_create()创建的任务行为完全相同,但是不能使用task_delete()函数删除静态创建的任务。
任务模块自动创建Task_idle任务,并赋予它最低的任务优先级(0)。当没有更高优先级的Hwi、Swi或Task正在运行时,它运行为空闲对象定义的函数。
将任务配置为相同的优先级时,它们将按照它们在配置脚本中的创建顺序执行。任务最多有32个优先级,默认为16 个。最高级别是定义的优先级数减去1,最低级别是0。优先级0是为系统空闲任务保留的。不能通过设置order属性在单个优先级内对任务进行排序。
如果希望任务最初状态处于非活动状态,要将优先级设置为-1。在运行时提升优先级之前,这些任务就不会执行
Task Execution and Scheduling
每个任务对象总有下列4种执行状态的一个:
- Task_Mode_RUNNING,这意味着任务是在系统处理器上实际执行的任务
- Task_Mode_READY,这意味着任务的执行取决于处理器的可用性
- Task_Mode_BLOCKED,这意味着任务在系统内发生特定事件之前无法执行
- Task_Mode_TERMINATED:这意味着任务已“终止”,不再执行
- Task_Mode_INACTIVE:这意味着任务的优先级等于-1,并且处于预就绪状态。此优先级可以在创建任务时设置,也可以通过在运行时调用task_setPri()API来设置
任务是被根据应用程序分配的优先级来安排任务的执行。不能有多个任务同时运行。一般来说,没有一个就绪任务的优先级高于当前正在执行的任务,因为高优先级的就绪任务会抢占正在执行的任务。与许多分时操作系统不一样,当一个更高优先级的任务准备运行时,SYS/BIOS会立即抢占当前任务。
最高优先级的任务仍然可以调用Semaphore_pend()、task_sleep()或其他阻塞调用,已允许低优先级的任务运行。可以在运行时调用task_setPri()API来设置任务的优先级。
在一个程序的执行过程中,每个任务的执行模式会因多种原因而改变。下图是执行模式的改变:
Task、Semaphore、Event和Mailbox模块中的函数可以改变任务对象的执行状态:阻塞或终止当前正在运行的任务,准备以前挂起的任务,重新调度当前任务等。
有一个任务的执行模式为Task_mode_RUNNING。如果所有的程序任务都被阻塞,并且没有运行Hwi或Swi,Task将执行Task_idle任务,在系统中这个任务的优先级比所有其他任务的优先级都低。当一个任务被Hwi或Swi抢占时,task_stat()为该任务返回的任务执行模式仍然是task_mode_RUNNING,因为当抢占结束后,任务将运行。
当Task_Mode_RUNNING转换到其他三种状态中的任何一种时,control将切换到准备运行的最高优先级任务(即,其模式为Task_Mode_ready)。运行任务的任务模式通过以下方式转换到其他模式之一:
- 通过调用Task_exit(),正在运行的任务变为Task_Mode_TERMINATED,当任务从其顶级函数返回时,将自动调用该函数。所有任务返回后,任务管理器通过调用状态代码为0的System_exit()终止程序执行。
- 正在运行的任务在调用导致当前任务暂停执行的函数(例如,Semphore_pend()或者Task_sleep())时变为task_Mode_BLOCKED;任务在执行某些I/O操作、等待某些共享资源的可用性或空闲时会进入此状态。
- 正在运行的任务变为task_Mode_READY,并且在其他高优先级任务准备运行时被抢占。如果当前任务的优先级不再是系统中最高的,Task_setPri()会导致这种类型转换。任务也可以使用task_yield()来使其他任务具有相同的优先级。
当前处于Task_Mode_BLOCKED的任务,为响应某个特定的事件而转换到就绪状态,输入输出操作的完成、共享资源的可用性、指定时间的流逝等等。通过变为Task_Mode_REDAY,此任务将根据其优先级进行调度执行,当然,如果此任务的优先级高于当前正在执行的任务,则该任务将立即转换到运行状态。任务按照先到先得的原则安排同等优先级的任务。
Task Stacks
内核为每个任务对象维护一个处理器寄存器的副本。每个任务都有自己的运行时堆栈,用于存储本地变量以及进一步嵌套函数调用。
静态或动态任务创建时,可以分别为每个任务对象指定堆栈大小。每个任务堆栈必须足够大,以处理其正常函数调用和两个完全中断的Hwi上下文。
"Maximum Stack Consumed"列显示的是最坏情况下中断嵌套所需的堆栈空间。数字表示的是两个完整的Hwi中断上下文加上任务调度器为其局部变量使用的空间。附加的嵌套中断上下文被推送到公共系统堆栈上。
注意,当内核配置为没有Task Hooks时(Task.minimizeLatency = false and BIOS.logsEnabled = false),除了任务调度器的本地变量外,每个任务堆栈必须只支持一个完整的Hwi中断上下文。这个配置等于"Minimum Stack Consumed"
Target | Minimun Stack Consumed | Maximum Stack Consumed | Units |
---|---|---|---|
TI_C674 | 300 | 628 | 8-bits bytes |
当任务被抢占时,任务堆栈可能需要包含两个中断的Hwi上下文(如果任务被Hwi抢占)或者一个中断Hwi上下文和一个任务抢占上下文(如果任务被更高优先级的任务抢占)。由于Hwi上下文比任务上下文达,因此给出的数字时针对两个Hwi上下文的。如果任务阻塞,则只有C函数必须保存的寄存器才会保存到任务堆栈中。
找到正确堆栈大小的另一种方法是使堆栈的大小变大,然后使用CCS软件查找实际使用堆栈的大小
参考文献:
- 《TI-RTOS Kernel(SYS/BIOS) User’s Guide》