1. 任务与多任务
多任务环境允许实时应用程序由一系列独立的任务构成,这些任务拥有自己的执行与系统资源。
2. VxWorks系统任务
根据具体的配置,VxWorks在启动时将运行各种系统任务,其中有些任务会一直运行。
VxWorks基础任务如下:
可选组件任务如下:
3. 任务拥有权与继承属性
根用户是所有任务和RTP的默认拥有者。可以使用如下函数了解任务拥有权与继承属性:
- getuid()
- getgid()
- setuid()
- setgid()
- taskShow()
- ps -l (用于RTP)
4. 任务状态和转换
下表描述了在开发工具中课件的任务状态和状态符号。需要注意的是,任务状态是可以累加的,同一时刻一个任务可能处于多个状态下。
Shell命令行中的任务状态示例
基本的任务状态转换图示
下图展示了基本的任务状态转换关系。为了简化关系,图中没有展示上述的叠加状态,也没有展示STOP状态。
注意:taskSpawn()函数将创建一个任务,并使之进入Ready状态;taskCreate()函数将创建一个任务,并使之进入suspend状态。
5. 任务调度
多任务环境需要任务调度器将CPU分配给处于ready状态的任务。VxWorks提供了多种调度器选项:
- 传统VxWorks调度器,提供基于优先级的抢占调度,具备round-robin扩展;
- VxWorks POSIX线程调度器,用于运行进程中的线程(RTP)
- RTP分时调度器,允许按照时间片调度RTP;
- 自定义调度器框架,允许自定义开发调度器;
任务优先级
任务优先级在创建时指定,任务调度器依赖于优先级进行调度。VxWorks内核提供了256个优先级,最高优先级为0,最低优先级为255。
内核应用程序优先级
所有应用程序应该运行在优先级100~255。
注意:网络应用程序任务的优先级可能需要运行在低于100的优先级下。
驱动程序的任务优先级
驱动任务优先级范围为51~99。
任务倒置:将一个内核任务移动到优先级队列的队尾
可使用函数taskRotate()实现该功能,结合该函数可以间接实现round-robin机制。
6. 任务创建与激活
taskLib库中提供了创建、控制任务的函数,也提供了获取任务信息的函数。如下所示:
7. 任务名称与ID
taskLib中提供的任务名称和ID函数如下所示:
8. 任务选项
略
9. 任务栈
任务的栈空间是在任务创建时定义的。可以使用guard zone使任务栈不可执行,从而对任务栈进行保护。
想要确切知道一个任务需要多大栈空间是很困难的。为了避免栈溢出与崩溃,可以在分配任务栈时分配一个比预期大小更大的空间。之后可以使用checkStack()函数或ti()函数周期性地检查任务栈。当确认了具体的使用情况后,可以调整栈大小以适应测试或系统部署的要求。
任务栈保护
可以使用guard zone通过将任务栈设置为不可执行,来实现任务栈保护。
任务栈guard zone
通过配置INCLUDE_PROTECT_TASK_STACK组件,可以为任务使能guard zone保护功能。如果对系统内存要求比较严格,后续在进行最终测试或系统部署时可以移除该组件。
在任务执行时,一个对上的guard zone可以确保任务栈不超过其预定义的大小上限,以免搞崩其他数据或任务栈;一个对下的guard zone可以确保对任务栈的访问不低于其栈底空间,以免于由缓冲区移除导致的内存崩溃。
10. 任务信息
任务信息是动态的,除非任务挂起,否则任务信息所反馈的信息可能不是最新的。可以使用如下函数获取任务信息。
11. 任务执行控制
以下函数可用于控制任务的执行状态:
<p如果需要将任务延迟半秒,可以使用如下方式:
taskDelay(sysClkRateGet()/2)
其中,sysClkRateGet()函数返回了每秒的系统时钟数。使用taskDelay(0),可以直接将CPU使用权让给其他任务,使自己挂起并让同优先级 的其他任务继续执行。
12. 任务调度控制
可使用如下函数实现任务调度控制。
13. 任务删除及删除保护
任务可以被动态地删除,也可以通过保护措施避免被其他任务删除。具体函数如下:
删除保护
任务在执行关键代码时,为了避免被删除,可以通过增加其删除保护计数器来实现任务保护。具体方法包括:
- 调用taskSafe();
- 获取使用了SEM_DELETE_SAFE选项的互斥信号量。
对于使用SEM_DELETE_SAFE选项的信号量,在使用semTake()获取它时,效果类似于调用taskSafe();在使用semGive()释放它时,效果类似于调用taskUnsafe()。
当任务执行完关键代码后,为了允许被其他函数删除,需要减少其删除保护计数器。具体方法包括:
- 调用taskUnsafe();
- 释放具有删除保护属性的互斥信号量。
14. 任务扩展:使用钩子函数
VxWorks提供钩子函数管理API,用于注册在创建、删除或任务切换时所需触发的钩子函数。具体函数接口如下:
15. 任务错误状态:errno
C函数库中使用了一个全局整型变量errno,用于反馈函数执行错误时的具体错误码。此由ANSI C标准中所规定。
注意:当前描述的内容主要针对VxWorks,对于SMP需要另外考虑。
errno的分层定义
在VxWorks内核中,同时使用了两种方法定义errno:
- ANSI C全局变量errno;
- errno.h中定义的一个宏errno,该宏定义调用一个函数__errno()。该函数返回全局变量errno的地址。使用该方法的好处是:因为__errno()是一个函数,所以可以在调试时为其添加断点,从而确定是否有错误发生。
每个任务具有独立的errno值
为了在多任务环境下使用errno,VxWorks为每个任务保留了相应的errno。因此,在每次进行任务切换时,内核将errno作为任务栈的一部分保存在任务栈中。
16. 任务异常处理
信号(signal)可以用于标识软件或硬件异常。
17. 共享代码与重入
供多个任务执行的一份代码被称为共享代码,共享代码必须是可重入的。
18. 内核任务环境变量
默认情况下,内核任务共享相同的环境变量。但是如果一个任务在创建时使用了VX_PRIVATE_ENV选项,那么它就可以拥有私有的环境变量。
envLib环境变量API
envLib库提供了兼容Unix的环境变量功能。具体函数结果如下: