任务的出现是区分实时操作系统和裸机系统的根本。对于裸机系统来说,只有一个任务,即一个超循环。对于实时操作系统来说往往是一个多任务的环境。一个任务运行的时候好像是它独享着整个系统的资源,对于单核的cpu来说,任何一个时刻只有一个任务在运行。
raw os 创建任务的函数为raw_task_create。
任务的形式通常为一个无限循环。示例如下:
void task(void *p_arg)
{
...................
while (1) {
...................
...................
}
}
可以看到任务是没有返回值的。任务的实体是一个无限循环体。
多任务系统环境中具有一个挑战性的问题是任务的栈空间溢出问题,这个问题本质上除非使用mmu或者mpu, 不然软件上是永远无法百分百侦测栈溢出问题的。软件无法侦测的原因可能是任务内部申请了一个比较大的局部变量数组,直接跳跃超出了栈访问。既然100%无法保证,那还有意义去使用软件侦测栈空间吗?答案是肯定的,绝大部分情况下,使用软件侦测是没问题的。
raw os的软件栈侦测机制除了主动调用任务api raw_task_stack_check来侦测任务栈的空闲空间外,空闲任务也会时刻监视系统各任务栈的空间,具体查看空闲任务一章节。
任务的管理也包括对时间的管理,raw os 系统中任务允许主动睡眠一段时间然后时间到了醒过来。系统中主动睡眠的函数有raw_sleep 以及raw_time_sleep。
raw os 系统也提供了开关抢占的函数:raw_disable_sche以及raw_enable_sche。
raw_disable_sche被调用之后,即使有高优先级的任务就绪也无法相应,直到再次开抢占之后切换到高优先级任务,如果其中有更高优先级任务被唤醒了。
关系统抢占的函数,强烈不建议用户去使用,因为那样会增加系统最大的任务延迟时间,对系统实时性是相当害的。
raw os 系统提供了挂起和回复任务的操作,api函数为raw_task_suspend和raw_task_resume,支持任务嵌套的suspend状态。
raw os 系统提供了动态改变任务的优先级的函数raw_task_priority_change,使用此函数有一个设计原则,任务自己改变自己的优先级,而不是其他任务去改变。遵循这样的设计原则,系统行为将更加的可测。
raw os 系统提供了任务删除的函数raw_task_delete, 但是使用此函数也是有具体要求的,第一需要自己删除自己,第二删除自己之前必须释放所有的锁。因为任务删除之后如果还持有锁的话,其它任务势必永远获得不了锁。第三任务很可能需要释放自己申请的内存,如果不这样的话,任务删除之后,内存势必不能回收,造成系统的内存泄漏。
raw os 系统提供了任务的一组私有变量,这些变量是每个任务所独有的信息。相关的函数为raw_set_task_user_point和raw_get_task_user_point。
raw os系统可以指定具体每一个任务的调度行为,即每一个任务可以赋予SCHED_FIFO和SCHED_RR的调度行为。SCHED_FIFO和SCHED_RR的调度是遵循工业标准posix的行为去调度的。具体的调度行为请参照实时操作系统主流调度方法一章节。
raw os系统提供了中止任务等待系统资源的api, 假设任务task1等待在信号量上,另一任务task2如果不想让task1继续等待的话,可以调用raw_task_wait_abort随时中止task1的等待。
raw os系统提供了一些关于系统debug的api, raw_iter_block_task 能够遍历阻塞在系统资源上的所有任务,并作出一定的回调操作。raw_get_system_global_space函数用于得到系统所使用到的所有数据段的空间。
综上所述,可以看到raw os 的任务管理系统涵盖到了大量的api, 事实上绝大部分的实时操作系统的api都实现了类似的功能。
任务状态
基于实时操作系统的设计都具有任务的概念,任务都具有状态的属性。任务的状态各家实时操作系统基本上都是共同的,一般是就绪状态,阻塞状态。raw os 的任务状态一定程度上参考了ucos 3 的设计,任务的状态分得很细,有助于避免实时系统的深层次bug。
raw os 具体的任务状态图如下:
file:///C:/Users/ASUS/AppData/Local/Temp/ksohtml/wps_clip_image-22845.png
下面会详细讲解这张图,这张图理解了,基本对各家实时操作系统的任务状态也理解差不多了。
RAW_RDY是任务的一个起始状态,也就是任务的就绪态。RAW_DLY是任务的睡眠状态,由raw_sleep这个api来触发进入此状态。RAW_SUSPENDED的状态由raw_task_suspend来触发进入此状态, 任务进入RAW_SUSPENDED的状态后,可以被其他任务调用task_resume来恢复到RAW_RDY状态。RAW_PEND状态是任务的阻塞状态,是任务得不到系统的事件引起的,比如任务运行raw_queue_receive,当queue里面没有消息的时候,任务就会进入RAW_PEND状态直到消息到来。如果任务运行raw_queue_receive被阻塞的时候,任务希望在得不到消息的时候,会超时自己醒过来,这个时候任务会进入RAW_PEND_TIMEOUT状态而不是RAW_PEND状态。另外一点是任务处于RAW_DLY, RAW_PEND,RAW_PEND_TIMEOUT,的时候,可以再被叠加一个SUSPEND状态。实际情况举例如下:
假设任务task 1 调用raw_queue_receive,但是queue里面没有消息,task 1 希望100ms后就超时退出这个函数不再等待。这个时候task 1 会进入RAW_PEND_TIMEOUT状态。在task 1 等待消息期间,假设任务task 2 再运行,task2 调用raw_task_suspend使task 1进入suspend状态,这个时候task 1 的任务状态会叠加为RAW_PEND_TIMEOUT_SUSPENDED。
总结,理清楚任务的状态图,对理解实时操作系统的api行为是有极大帮助的。raw os的任务细分状态图比起其它实时系统的任务状态图更为细腻,从根本上清楚了系统潜在的深层处bug。
Task api 应用
1 RAW_U16 raw_task_create(RAW_TASK_OBJ *task_obj, RAW_U8 *task_name, RAW_VOID *task_arg, RAW_U8 task_prio, RAW_U32 time_slice, PORT_STACK *task_stack_base, RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start)
函数功能:此函数创建了一个任务。函数注意点: stack_size是指栈空间的栈元素,注意不是指具体的字节大小。
此函数的参数有9个,分别含义如下:
task_obj 为任务控制块的地址。
task_name 是这个任务的名字。
task_arg 是往该任务传递的参数。
task_prio 是任务的优先级,数值越小,优先级越高,优先级0以及空闲任务的优先级只允许有一个。
time_slice是分配给任务的时间片。
task_stack_base是任务的栈底地址。
stack_size是栈空间大小。
task_entry是任务的入口函数。
auto_start决定任务是否创建后进入就绪状态。
函数的返回值:
RAW_SUCCESS
2 RAW_U16 raw_task_stack_check(RAW_TASK_OBJ *task_obj, RAW_U32 *free_stack)
函数功能:此函数创建了一个任务。
此函数的参数有2个,分别含义如下:
task_obj 为任务控制块的地址。
free_stack会返回任务具体的空闲栈空间元素。
函数的返回值:
RAW_SUCCESS
3 RAW_U16 raw_disable_sche()
函数功能:关掉系统抢占。函数注意点:此函数会影响系统最大的任务延迟,对系统的实时性有损害,强烈不建议用户使用此函数。
此函数的参数无。
函数的返回值:
RAW_SUCCESS
4 RAW_U16 raw_sleep(RAW_TICK_TYPE dly)
函数功能:此函数会导致任务睡眠,任务状态会转为RAW_DLY。
此函数的参数有1个,含义如下:
dly为任务需要睡眠的实际时间,时间以tick为计算单位。dly 参数为0的时候实现任务yield功能,即任务放到就绪队列最后面。
函数的返回值:
RAW_SUCCESS
RAW_BLOCK_ABORT为任务在睡眠时期被打断。
RAW_BLOCK_DEL为任务在睡眠时期被其它任务删除。
5 RAW_U16 raw_time_sleep(RAW_U16 hours, RAW_U16 minutes, RAW_U16 seconds,RAW_U32 milli)
函数功能:此函数会导致任务睡眠,任务状态会转为RAW_DLY。
此函数的参数有4个,含义如下:
hours 为睡眠实际的小时,取值范围为0-999
minutes为睡眠实际的分钟,取值范围为0-9999
seconds为睡眠的实际秒数,取值范围为0-65535
milli为睡眠的实际毫秒数,取值范围为0-4294967295
函数的返回值:
RAW_SUCCESS 函数操作成功。
RAW_BLOCK_ABORT为任务在睡眠时期被打断。
RAW_BLOCK_DEL为任务在睡眠时期被其它任务删除。
6 RAW_U16 raw_task_suspend(RAW_TASK_OBJ *task_ptr)
函数功能:指定的函数会进入挂起状态。即该任务会放弃cpu使用权。任务可以被多次挂起,也就是说,任务支持挂起嵌套。此函数不能在中断以及task 0事件回调函数中使用,否则有一定几率函数功能无效。
此函数的参数有1个,含义如下:
task_ptr为将进入挂起状态任务的实体地址。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_SUSPEND_TASK_NOT_ALLOWED:空闲任务和优先级为0的任务是不能被
挂起的。
RAW_STATE_UNKNOWN:被挂起的任务状态有问题。
RAW_SUCCESS 函数操作成功。
7 RAW_U16 raw_task_resume(RAW_TASK_OBJ *task_ptr)
函数功能:指定的函数会解除挂起状态,如果任务处于挂起的嵌套状态, 会使
任务减少一层挂起状态
此函数的参数有1个,含义如下:
task_ptr为将任务的实体地址。
函数的返回值:
RAW_SUCCESS 函数操作成功。
8 RAW_U16 raw_task_priority_change (RAW_TASK_OBJ *task_ptr, RAW_U8 new_priority, RAW_U8 *old_priority)
函数功能:改变指定任务的优先级。此函数调用的时候强烈建议让任务自己改变
自己的优先级。
此函数的参数有3个,含义如下:
task_ptr为将要被改变优先级的任务。
new_priority为任务将要被改变的优先级。
old_priority会保存任务改变之前的优先级,即原来的优先级。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_NULL_OBJECT:输入输出参数非法。
RAW_CHANGE_PRIORITY_NOT_ALLOWED:不能改变优先级为0的任务和空闲任务。
RAW_EXCEED_CEILING_PRIORITY:改变的优先级超过了mutex锁的置顶优先级。
RAW_STATE_UNKNOWN:任务非法状态。
RAW_SUCCESS 函数操作成功。
9 RAW_U16 raw_task_delete(RAW_TASK_OBJ *task_ptr)
函数功能:删除指定的任务。此函数调用的时候必须满足两点,第一让任务自己删除自己,第二任务删除自己之前,必须释放所有的锁和申请的内存,不然会造成内存泄漏。
此函数的参数有1个,含义如下:
task_ptr为即将被删除的任务。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_NULL_OBJECT:输入参数非法。
RAW_DELETE_TASK_NOT_ALLOWED:不能删除优先级为0的任务和空闲任务。
RAW_SUCCESS 函数操作成功。
10 RAW_VOID raw_set_task_user_point(RAW_TASK_OBJ *task_ptr, RAW_VOID *user_point, RAW_U32 point_position)
函数功能:设置任务的私有属性。
此函数的参数有3个,含义如下:
task_ptr为即将被设置私有属性的任务。
user_point为设置的私有属性。
point_position为任务内部私有属性的空间位置。
11 RAW_VOID *raw_get_task_user_point(RAW_TASK_OBJ *task_ptr, RAW_U32 point_position)
函数功能:得到任务的私有属性。
此函数的参数有2个,含义如下:
task_ptr为即将被得到私有属性的任务。
point_position为任务内部私有属性的空间位置。
函数的返回值:
任务的私有属性。
12 RAW_U16 raw_task_time_slice_change(RAW_TASK_OBJ *task_ptr, RAW_U32 new_time_slice)
函数功能:设置任务的时间片。
此函数的参数有2个,含义如下:
task_ptr为将要被设置时间片的任务。
new_time_slice为任务新的时间片,new_time_slice为0时设置任务的系统默认时间片 。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_SUCCESS 函数操作成功。
13 RAW_U16 raw_set_sched_way(RAW_TASK_OBJ *task_ptr, RAW_U8 policy)
函数功能:设置任务的调度方式。
此函数的参数有2个,含义如下:
task_ptr为即将被设置调度方式的任务。
policy为设置任务的调度属性。支持的参数有posix标准的调度方式SCHED_FIFO和SCHED_RR。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_SUCCESS 函数操作成功。
14 RAW_U16 raw_get_sched_way(RAW_TASK_OBJ *task_ptr, RAW_U8 *policy_ptr)
函数功能:得到任务的调度方式。
此函数的参数有2个,含义如下:
task_ptr为即将被得到调度方式的任务。
policy为得到任务的调度属性。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_SUCCESS 函数操作成功。
15 RAW_U16 raw_task_wait_abort(RAW_TASK_OBJ *task_ptr)
函数功能:中止异常等待状态的任务,比如中止等待seamphore, mutex, event, sleep 等等。
此函数的参数有1个,含义如下:
task_ptr为即将被中止等待的任务。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_SUCCESS 函数操作成功。
16 RAW_TASK_OBJ *raw_task_identify()
此函数的参数无。
函数功能:得返回当前运行的任务。
函数的返回值:
RAW_SUCCESS 函数操作成功。
17 RAW_U16 raw_iter_block_task(LIST *object_head, RAW_VOID (*debug_function)(RAW_TASK_OBJ *), RAW_U8 opt)
函数功能:用来遍历内核对象上阻塞的任务,通常用作debug。
此函数的参数有3个,含义如下:
object_head:内核对象的链表头。
debug_function:用户回调函数。
opt:是否唤醒任务,正值唤醒。
函数的返回值:
RAW_NOT_CALLED_BY_ISR:不能在中断中使用。
RAW_SUCCESS 函数操作成功。
18 RAW_U32 raw_get_system_global_space()
函数功能:用来得到raw os锁消耗的全局变量,即可以得到raw os数据段的消耗空间。
此函数的参数无。
函数的返回值:
RAW_SUCCESS 函数操作成功。