VxWorks 6.9 内核编程指导之读书笔记 -- 多任务
- 概述
- VxWork系统任务
- 任务调度
- 任务创建和管理
- 任务的错误状态
- 任务异常处理
- 共享代码和重入
概述
现代实时操作系统是基于多任务和任务间通信的概念的。多任务环境运行一个实时进程RTP可以被作为一系列相互独立的任务集,每一个任务都有自己的执行线程和系统资源。任务是VxWorks调度的基本单元。所有任务,不管是在内核中,还是进程中,使用相同的调度(VxWorks进程本身不被调度)。
任务的概念与其他操作系统的线程概念比较类似。多任务为应用程序对多个孤立的实时事件的控制和反应对提供了基础。在单核处理器(UP)系统中,多任务呈现了多个任务同时执行的表象,实际上,内核在调度策略的基础上交替执行这些任务。
每个任务都有自己的上下文,即任务被内核调度运行时能访问的CPU环境和系统资源。上下文切换时,认为的上下文被保存在任务控制块中(TCB)。
TCB包含
- 执行的线程;即任务的程序计数器
- 任务的虚拟内存上下文(如果CPU支持且被包含)
- CPU寄存器和可选的协处理器的寄存器
- 动态变量和函数调用的栈
- 分配给标准输入、输出和错误的I/O
- 一个延时定时器
- 内核控制结构
- 信号处理器
- 任务的私有环境(环境变量)错误状态(errno)
- 调试和性能监视值
如果,VxWorks禁用RTP的支持(INCULDE_RTP),任务上下文不包含它的虚拟内存。所有任务仅运行在单一地址空间(内核)。
然而,如果VxWorks启用了RTP的支持,不管进程是否被激活,内核任务的上下文包含了虚拟内存上下文,因为系统有可能与内核之外的虚拟内存上下文打交道。即,系统可能有任务运行在几个不同的虚拟内存上下文中(内核和一个或多个进程)。
任务的状态和转变
内核维护在系统中的任务的当前状态。作为活动结果,任务将从一个状态转化为另一个状态,如被应用程序调用的某种函数(如在信号量无法使用时,试图获取信号量)和使用开发工具如调试器。
在就绪状态的最高优先级的任务将被执行。当任务用taskSpawn创建时,它们立即进入就绪状态。
当任务通过taskCreate或带有VX_TASK_NOACTIVATE选项参数的taskOpen函数创建时,它们被实例化为suspend状态。稍后可以调用taskActivate来使它们进入就绪状态。激活阶段非常快,使得应用程序能以及时的方式创建和激活它们。
任务状态
状态 | 描述 |
READY | 任务除了等待CPU没有等待其它任何资源。 |
PEND | 由于资源不可用,任务在等待资源。 |
DELAY | 任务在睡眠。 |
SUSPEND |
任务无法执行(不是PEND或DELAY)。这种状态主要用于调试。挂起不会禁止状态转变,只是执行。因此,pended-suspended任务仍然不会阻塞, delayed-suspended任务能够被唤醒。 |
STOP | 任务被调试器停止(也被错误检测和报告功能使用) |
DELAY + S | 任务既处于delayed,也处于suspended |
PEND + S | 任务既PENDED也SUSPENDED |
PEND + T | 任务被搁置带有超时值 |
STOP + P | 任务被搁置和停止(被调试器,错误检测和报告功能,或SIGSTOP信号) |
STOP + S | 任务被停止和挂起 |
STOP + T | 任务被延时和停止(被调试器,错误检测和报告功能,或SIGSTOP信号) |
PEND + S + T | 任务被搁置带有超时值并挂起 |
STOP + P + S | 任务被调试器搁置,挂起和停止 |
STOP + P + T | 任务被调试器搁置带有超时和停止 |
STOP + T + S | 任务被调试器挂起,延时和停止 |
ST + P + S + T | 任务被调试器搁置带有超时,挂起和停止 |
state + I | 任务被state指定(任何状态或上面状态的组合)加上内在的优先级。 |
STOP状态被调试器使用,当断点被执行时。也可以被错误检测和报告功能使用。
状态转变
VxWorks的系统任务
VxWorks在引导时启动的系统任务依赖于配置,有些总是运行。任务集与VxWorks的基本配置相关,很少的任务常用于可选的组件。
注意:别挂起、删除或改变任何系统任务的优先级。否则将导致不可预期的系统行为。
更多信息请看另外一篇随笔
任务调度
多任务要求任务调度器分配CPU给就绪的任务。VxWorks提供了以下调度选项:
- 传统的调度,提供基于优先级,抢占式及循环调度。
- VxWorks的POSIX线程调度,专门为RTP设计。
- 自定义调度框架,允许你开发自己的调度算法。
任务优先级
任务调度依赖于创建任务时指定的优先级。内核提供了256种优先级,0到255。0是最高优先级,255是最低优先级。在创建时指定了优先级,但是也可以在稍后编程修改它的优先级。
应用程序任务优先级
所有应用程序的任务优先级都在范围100到255.
注意:网络应用程序任务的优先级可以在100以内。
驱动任务优先级
相对与应用程序的任务优先级从100到255,它的任务优先级(与ISR相关的任务)可以是51到99。这些任务比较关键;举个例子,如果从芯片拷贝数据的任务失败,设备将丢失数据。驱动支持的任务包括tNet0,HDLC等。
tNet0的优先级是50,所以用户不应该分配的优先级低于该任务。如果低于,则将导致网络连接挂掉并阻止主机工具的调试功能。
VxWorks传统调度器
传统调度提供了基于优先级的抢占式调度及可选的可编程的循环调度。传统调度可以参考original或native调度。
传统调度默认被INCLUDE_VX_TRADITIONAL_SCHEDULER组件包含。
基于优先级的抢占式调度
当更高优先级的任务就绪时,当前任务被抢占。因此,CPU总是确保就绪的最高优先级的任务被执行。
这种调度策略的缺点是,多个相同优先级的任务必须共享处理器,如果单个任务永远不阻塞,它可能霸占CPU。因此其它相同优先级的任务将永远不会被执行。循环调度解决了这个办法。
调度和就绪队列
调度器维护了一个FIFO的队列,该队列包含了在系统中每个优先级的所有就绪的任务。当CPU可用时,排在前面的任务被调度。
任务在就绪队列中位置可能改变,取决于以下因素:
- 如果认为被抢占,调度器运行高优先级任务,但是被抢占的任务仍然保留在该优先级列表中的前面的位置。
- 如果认为被搁置,延时,挂起或停止,它将从就绪列表中被删除。当它随后再次就绪时,它被放在该优先级列表的尾部。
- 如果优先级通过taskPrioritySet被改变,它被放在心优先级列表的尾部。
- 如果认为的优先级是基于互斥信号量优先级而临时提高的,它执行之后将被放在它本来优先级的列表的尾部。
移动任务到优先级列表的尾端
taskRotate函数用于移动任务从优先级列表的前部到尾部。如taskRotate(100),它将把从100优先级列表中的前面的任务移到尾部。如果要移动本任务到尾部,则使用TASK_PRIORITY_SELF作为参数传递给taskRotate函数,而不是优先级的数值作为参数。该函数可用于替代循环调度。它可以控制相同优先级的就绪任务之间共享CPU,而不是让系统以相同的间隔来决定。
循环调度
循环调度是对于基于优先级调度的扩展。循环调度运行相同优先级的任务共享CPU。循环调度通过时间片来共享CPU。相同优先级的一组任务中的每一个任务在交出CPU之前,都执行一定的时间间隔,或时间片。因此,它们中没有哪个任务可以一直占有CPU。时间片用完则该任务将被放在该优先级列表中的尾部。
VxWorks的循环调度不像其它操作系统,它的任务是可以被更高优先级任务抢占的,更高优先级完成后,它继续执行未完成的任务。
启用循环调度
可以使用参数时间片来调用kernelTimeSlice启用循环调度。如果参数为0,则禁用循环调度。
时间片计数和抢占
每个任务可以执行相同的时间片。如果循环调度启用,抢占被执行的任务也启用,系统的tick处理器将增加时间片计数。当指定的时间片用完,系统tick处理器将清0任务的时间片计数,任务被放在该优先级列表的尾部。启用循环调度不影响任务上下文切换的性能,也不分配额外的内存。
如果任务被更高优先级任务抢占或阻塞,则它的时间片计数将被保存,并在继续执行时,执行剩余的时间。由于任务被抢占,任务实际执行的时间比分配给它的时间片多一点或少一点都是可能的。
任务状态错误码
ANSI C标准中有errno一个全局整数值来存放错误码。然而,errno也被定义成一个宏,对于VxWorks的所有函数来说,该宏定义为调用__errno()。而对于其它的函数来说,该宏定义为ANSI C标准中errno的地址,因此对于标准ANSI C的函数,该宏其实就是errno整数值。
在VxWorks,errno是一个预定义全局变量,可以被应用程序直接使用。然而,对于多任务的环境,每个任务必须访问自己的errno。因此errno被内核作为任务的上下文保存和恢复。
类似的,中断服务程序也有errno。
几乎所有的VxWorks函数都遵守一个约定:通过返回值来指示函数成功或失败。很多函数仅返回成功或失败;有些函数通常返回非负值表示成功,返回ERROR表示失败。返回指针的函数,通常返回NULL(0)表示失败。很多情况,返回错误的情况下也设置了errno值来指明发生什么错误。
全局的errno永远不会被VxWorks清除,因此,它的值总是指示最后发生的错误。当VxWorks函数调用别的函数发生错误时,它不会修改底层的errno,而是返回自己的错误,因此,你可以得到errno来查找底层发送的错误。建议你也使用这种机制。可以通过printErrno来显示错误信息,如果errno有相应的字符串常量在错误状态符号表中(statSymTbl)。
错误值的分配
errno使用最重要的2个自己来表示发生错误的模块,用最不重要的2个自己来表示发生的错误。所有VxWorks模块都在范围1到500。带有0模块号的errno用于源码兼容。
所有其他errno值(大于或等于(501<<16)正数和所有负数)都可以被应用程序使用。更多信息参考errnoLib类库。
异常处理
程序的代码和数据发生错误会引起异常条件如非法指令,总线或地址错误,被0整除等。VxWorks的异常处理包会处理这些异常。
如果为某个异常使用自己的异常处理,则通过signal会捕获到异常,但默认的异常处理将被禁用。用户自定义异常对于从灾难中恢复是非常有用的。通常setjmp和longjmp会被使用。
共享代码和重入
代码被几个任务同时调用而不会冲突,则该代码是可共享的,也是可重入的。大多数Vxworks的函数是可重入,但是也有一些是不可重入的。如果函数有相应的_r版本的函数,则该函数是不可重入的,而_r函数是可重入的,如ldiv()函数有相应的ldiv_r(),所以ldiv是不可重入的,而ldiv_r()是可重入的。
I/O和驱动是可重入,但是要求应用程序小心设计。对于带缓冲的I/O,风河公司建议使用基于每个任务的文件指针缓存。在驱动层,由于全局文件描述符表,很可能从不同的任务的流中加载到缓存。如报文驱动可能从不同的任务接收报文混合到流中,每个报文都有自己的目的地。
VxWorks使用了以下重入技术
- 动态栈变量 -- 没有自己的数据,数据都是作为参数传递进来。
- 用信号量保护的全局和静态变量
- 任务变量
注意:在有些情况无法重入。此时应该使用二进制信号量来保护,或者在ISR中使用intLock和intUnlock。初始化函数应该可以被调用多次,即使逻辑上应该只能被调用一次。作为规则,函数应该避免使用静态变量来保存状态信息。但是初始化函数是个例外;使用静态变量来返回初始化函数成功与否是合适的。
VxWorks 6.9 内核编程指导之读书笔记 -- 多任务的更多相关文章
- VxWorks 6.9 内核编程指导之读书笔记 -- 多任务(二)
VxWorks的系统任务 VxWorks在引导时启动的系统任务依赖于配置,有些总是运行.任务集与VxWorks的基本配置相关,很少的任务常用于可选的组件. 注意:别挂起.删除或改变任何系统任务的优先级 ...
- VxWorks 6.9 内核编程指导之读书笔记 -- ISRs和Watchdog Timer
中断服务程序 ISR 硬件中断处理是实时系统的关键,因为它是外部时间通知系统的方式. ISR亦称为中断处理函数,是对中断的正确响应.可以使用任何ISR连接到任何没有被VxWorks使用的中断上.当关联 ...
- VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks kernel application (一)
#1 什么是内核应用程序? #2 开发内核应用程序注意事项 什么是内核应用程序? 内核应用程序不同于RTP程序,它允许在内核态,与操作系统使用相同的地址空间.因此,它与操作系统会相互干扰.它可以编译成 ...
- VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks Small-Footprint Configuration
什么是Small-footprint? Small-footprint常见关键配置? 如何配置Small-footprint? 什么是Small-footprint? Small-footprint配 ...
- VxWorks 6.9 内核编程指导之读书笔记 -- POSIX
POSIX能力 VxWorks扩展了POSIX,为了移植,VxWorks提供了额外的POSIX接口作为可选组件.VxWorks实现了POSIX 1003.1(POSIX .1)一些传统接口以及POSI ...
- VxWorks 6.9 内核编程指导之读书笔记 -- Singnals
Signals 信号是操作系统用于异常处理和异步控制流的关键.在很多方面,信号相当于软件方面的硬件中的中断.操作系统产生的信号包括总线错误和浮点处理异常.信号也提供了API来管理和产生信号.在应用程序 ...
- VxWorks 6.9 内核编程指导之读书笔记 -- C++开发
5.1 介绍 针对C++的VxWorks配置 C++头文件 使用C++启动任务 C和C++之前调用代码 C++编译器说明 在信号处理和ISR中使用C++ 下载C++编写的内核模块 C++编译器的不同 ...
- VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks Kernel application (二)
#1 内核对象的静态实例化 内核对象的静态实例化 任务的静态实例化 VX_TASK宏用来在编译时声明一个任务对象.该宏带有2个参数:任务名和栈大小.不像taskSpawn函数,任务名称可以是NULL. ...
- 《Linux/Unix系统编程手册》读书笔记9(文件属性)
<Linux/Unix系统编程手册>读书笔记 目录 在Linux里,万物皆文件.所以文件系统在Linux系统占有重要的地位.本文主要介绍的是文件的属性,只是稍微提及一下文件系统,日后如果有 ...
随机推荐
- ASP.NET过滤HTML标签只保留换行与空格的方法
这篇文章主要介绍了ASP.NET过滤HTML标签只保留换行与空格的方法,包含网上常见的方法以及对此方法的改进,具有一定的参考借鉴价值,需要的朋友可以参考下 本文实例讲述了ASP.NET过滤HTML ...
- 【JavaScript】Object.observe()带来的数据绑定变革
Object.observe()带来的数据绑定变革 引言 一场变革即将到来.一项Javascript中的新特性将会改变你对于数据绑定的所有认识.它也将改变你所使用的MVC库观察模型中发生的修改以及更新 ...
- JSAPI用户手册
本文档主要涵盖如何嵌入SpiderMonkey javascript引擎到你自己的c++程序中. JavaScript在浏览器端已经被广泛使用了.但是,Mozilla的javascript引擎可以被嵌 ...
- Android组件的通讯——Intent
转载:Android组件的通讯-Intent 1.概述 一个应用程序的三个核心组件——activities.services.broadcast receivers,都是通过叫做intents的消息激 ...
- Feister network
在密码学中,Feister network(又叫Feister Function, 一下简称 F函数)是一种用在块加密上的对称结构,很多种块加密算法都是使用这种结构. 优点: 1.加解密的过程非常相似 ...
- Mingw:在Linux系统下编译Windows的程序
Ubuntu下可以直接安装: sudo apt-get install mingw32 mingw32-binutils mingw32-runtime 安装后编译程序可以: i586-mingw32 ...
- 动漫网站基于jquery的横向手风琴特效
今天给大家分享一款动漫网站基于jquery的横向手风琴特效.这款手风琴特效适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗.效果图如下: 在线预 ...
- [置顶] HashMap HashTable HashSet区别剖析
HashMap.HashSet.HashTable之间的区别是Java程序员的一个常见面试题目,在此仅以此博客记录,并深入源代码进行分析: 在分析之前,先将其区别列于下面 1:HashSet底层采用的 ...
- MAMP Pro3.5注册码
MAMP这个就不用介绍了,堪称MAC下的苏菲玛索,官方下载地址:https://www.mamp.info/en/mamp-pro/ ,400多大洋,土豪朋友请直接购买吧,正版还是要支持的. 和我 ...
- LeetCode48 Rotate Image
题目: You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwis ...