VxWorks开发-任务

内核实现基本原理

VxWorks内核维护三个队列:tick、Ready、active。
除此之外,还有一个队列涉及任务,即资源等待队列,可以是VxWorks内核提供的,也可以是用户提供,此处为pend队列。

  • tick队列,调用taskDelay函数后,任务所处的队列,此时任务设置为Delay,无资格竞争CPU。
  • ready队列,有资格竞争使用CPU的所以任务,队列以优先级排序,队列头是除了运行的任务之外,系统中最高优先级的任务
  • active队列,系统中所有运行的任务
  • pend队列,竞争使用资源,资源不可用,进入pend队列

任务创建流程

使用taskSpawn创建一个新的任务,首先创建一个任务控制结构,对其初始化后,加入active队列作为系统任务管理,最后将其加入ready队列,此时才可竞争CPU。

任务优先级

VxWorks将任务分成256个优先级,0是最高优先级,优先级可以在调用taskSpawn时指定,用户也可以通过调用taskPrioritySet改变优先级,。

  • 应用层任务推荐使用100-250之间的优先级
  • 驱动层任务可以使用51-99之间的优先级
  • 网络数据收发任务tNetTask的优先级为50

VxWorks栈

不同于Linux,VxWorks下的任务自始至终都在使用一个栈,即使调用了内核函数,也不存在栈的切换,VxWorks栈的大小在创建时已经确定,之后不能改变,对于一个很多调用的函数,应该在创建时指定一个较大的任务栈。

任务上下文

任务在设计中有一个数据结构包含一个任务运行所需要的所有信息,这些信息称为上下文。

  • 平台CPU内部所有寄存器值
  • 任务运行时暂时存放函数变量以及函数调用时被传递参数的栈
  • 各种定时信息
  • 信号处理函数
  • 其他辅助信息,任务运行总时间,任务最终返回值

VxWorks系统时钟

每当时钟前进一个滴答(Tick),操作系统会响应一次中断,该中断为任务调度和定时器的触发点。

任务操作函数

使能RR调度接口,整体上仍然是优先级调度,在高有限级存在多个任务运行时,RR调度才有效。

1
2
3
4
5
STATUS kernelTimeSlice
{
int ticks
}
//循环调度方式,0则禁用,循环时间为ticks*tick S

在启动RR调度后,可以以参数0再次调用来禁用。

1
2
3
4
5
STATUS taskPrioritySet
{
int tid, //任务id,taskSpawn的返回值,
int newPriority //新设定的优先级
}

一个任务在运行过程中需要自己改变自己的优先级,将tid设置为0即可。

1
2
STATUS taskLock(void)
STATUS taskUnLock(void)
  • taskLock关闭任务调度,taskUnLock开启任务调度,主要保证一段代码的原子性。
  • taskLock不禁止中断,不能在中断上下文保证互斥。
  • 当taskLock因为资源进入阻塞状态,任务调度机制重新工作,直到该任务恢复运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
int taskSpawn
{
char* name, /*可以为NULL,采用默认任务名,‘tN’,N从1开始*/
int priority, /*任务优先级*/
int options, /*任务选项,控制任务的某些行为一般为0*/
int stackSize, /*任务栈的大小,此后不可更改*/
FUNCPTR entryPT, /*任务执行入口函数地址,函数名*/
int arg1,
...
...
...
int arg10 /*入口函数参数,最多10个,多于10个,可以使用指针*/
}

函数返回任务ID,可以通过ID获得TCB(task control block)地址

1
2
WIND_TCB* tPcb;
tPcb = taskTcb(0); //参数0将返回当前任务的TCB结构地址

使用taskSpawn创建一个任务,马上进入运行状态,有时候需要创建一个任务后进入挂起状态,可以使用taskCreate,函数参数与taskSpawn一样,但是需要调用taskActivate进行激活。

1
2
3
4
STATUS taskActivate
{
int tid
}

任务栈

  • VxWorks调度的基本单元是任务,也就是程序的实例
  • 参数存放在栈中,传递参数的机制多用栈
  • VxWorks的任务栈既被应用函数使用,也被内核函数使用
  • 任务栈的大小在创建时就决定了,一般先申请一个很大的栈,然后用试验法调用checkStack确定实际栈
    1
    2
    3
    4
    void checkStack
    {
    int taskNameOrId
    }

任务名

VxWork支持任意长度任务名,并不要求任务名的全局唯一性,任务名控制在11B以内

1
2
3
4
5
STATUS taskShow
{
int tid,
int level /*0显示大概信息,1显示详细信息,2显示所有任务信息*/
}

结束任务

1
2
3
4
STATUS taskDelete
{
int tid //为0结束自己
}

当删除一个占用资源没有释放的任务时,可能会导致崩溃。

1
2
STATUS taskSafe(void)
STATUS taskUnSafe(void)

在一个任务调用了taskSafe以后,在taskUnSafe之前,其他任何任务不能对其进行删除操作。

1
2
3
STATUS taskSuspend(int tid)         /*挂起任务*/
STATUS taskResume(int tid) /*恢复任务*/
STATUS taskDelay(int ticks) /*将正在运行的任务转为睡眠态,使用NO_WAIT作为参数时,VxWorks将当前任务置于ready队列所有相同优先级的任务之后*/

钩子函数–实现底功耗

可以使用一个最低优先级的后台任务加上一个任务调度钩子函数实现平台低功耗。当最低优先级后台任务被执行,触发钩子函数,使平台进入低功耗状态。

  • 任务创建钩子函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    STATUS taskCreateHookAdd
    {
    FUNCPTR createHook /*当一个新任务被创建时调用的钩子函数*/
    }
    void createHook
    {
    WIND_TCB *pNewTcb /*创建钩子函数形式,将会获取新创建的任务的TCB*/
    }
    void taskCreateHookDelete
    {
    FUNCPTR createHook /*注销通过taskCreateHookAdd注册的钩子*/
    }
  • 任务调度钩子函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    STATUS taskSwitchHookAdd
    {
    FUNCPTR switchHook /*注册发生任务调度时调用的钩子函数*/
    }
    void switchHook /*函数原型*/
    {
    WIND_TCB *pOldTcb, /*被调度出去的任务TCB*/
    WIND_TCB *pNewTcb /*抢占了CPU的任务TCB*/
    }
    STATUS taskSwitchHookDelete
    {
    FUNCPTR switchHook /*注销*/
    }
  • 任务删除钩子函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    STATUS taskDeleteHookAdd
    {
    FUNCPTR deleteHook /*注册在任务消亡时被调用的钩子函数*/
    }
    void deleteHook
    {
    WIND_TCB *pTcb /*函数原型*/
    }
    STATUS taskDeleteHookDelete
    {
    FUNCPTR deleteHook /*注销*/
    }
  • 钩子函数查询

    1
    2
    3
    void taskCreateHookShow(void)   /*显示当前注册到系统的所有在任务被创建时被调用的钩子函数列表*/
    void taskDeleteHookShow(void) /*显示当前注册到系统的所有在任务被删除时被调用的钩子函数列表*/
    void taskSwitchHookShow(void) /*显示当前注册到系统的所有在任务被调度时被调用的钩子函数列表*/
-------------本文结束感谢您的阅读-------------