REX是高通开发出来的一个操作系统,起初它是为了在Inter 80186处理器上应用而开发的,到后来才转变成应用在ARM这种微处理器上。他历经了很多版本,代码也越来越多,功能也越来越完善。REX只用不到5k的ROM存储空间,从前REX系统汇编代码和C代码加起来不过一千多行,不过现在已经超过一万五千行了。在功能提升的背后,不但要有高性能硬件的支持,同时要求系统的设计上也要更合理。

作为一个实时的嵌入式操作系统,REX有几个比较显著的特点:简单、高效、抢占式、多任务、实时。

简单,我们大家都能理解,嵌入式操作系统都有这样的共同的特点,它不像大型的操作系统一样提供各种各样的功能,它只须按照手机的基本需要来提供一些相应的功能即可,而且作为一个嵌入式操作系统,必须要求它有很小的功耗,这样才能手机在形状的大小上有合理的控制,也适合手机这种以电池供电的设备的需求。高效的,实时系统不是以每秒钟进行多少次运算来评价效率的,而是以对一个事件的响应时间和多久做完来评价的。REX是一个Real Time的系统,它要求对事件的反映速度要快,不能说用户按了一个key,系统等了几分钟都没有相应。REX系统不但响应的快,对事件的处理也快。REX系统是多任务的,在我们的感觉上,REX可以同时执行多个任务,这样也体现了高效的特点,但事实上它和其他的操作系统一样,也是以CPU在不同任务中的迅速轮转来实现形式上的多任务。这样就出现了一个问题:多任务在CPU之间如何轮转?这样就用到了REX的另一个特点:抢占式。REX是抢占式的,当一个最高优先级的任务一旦READY,它总能得到CPU的控制权,也就是说它可以抢占正在运行中的任务的CPU。以前的REX系统中每一个任务都有不同的优先级,总是能明确的比较出处于就绪态的任务中哪一个会获得CPU,但是到后来的REX版本中,允许不同的任务有相同的优先级,这就要求有另外一种调度方式,也就是在相同优先级的任务之间以时间片轮转的方式来调度。

上文中我们在讨论多任务和任务之间的调度,那么何为任务呢?在嵌入式实时操作系统中,任务就相当于线程。REX中有很多的TASK,我们可以把它们理解成都里运行的功能模块。每个任务都有自己独立的堆栈、运行空间、信号、队列等,它们之间是独立的、不互相干扰的,每个任务都实现一个相对独立的功能。但是每个任务都要求有自己独立的堆栈,这就要求在REX中不能有太多的任务,曾经Web Browser因为占用资源过多而被作为一个任务在REX中运行的,但是后来又把它放入BREW之中。我们要注意,不到万不得已不能新加任务。REX操作系统首先会建立一个idle task和main task,然后用main task来控制其他任务的创建。Main task也就是mc_task,在它被创建后它会首先创建一些非常重要服务如时钟、数据服务,数据库服务、Encoder Driver、RF Driver等等,之后才是定义和创建一些任务,首先它将sleep这个任务定义好,然后就是Dog Task,之后再是其他的任务,对于这些任务的内存拷贝、定义、开始服务的顺序我一直很迷惑,考虑到REX严格而周密的优先级制度,那么这些任务的貌似混乱的不同的定义顺序肯定也有其道理,虽然我至今尚迷惑于此,不过这样的确实现了mc_task的静态创建与mc_task对其他任务的动态创建。REX是通过rex_def_task()这个函数来定义任务的,这个函数先生成一个文间结构到stack,然后建立一个TCB跟这个任务相对应,然后再把task放到task list里。每个task都有自己的TCB,也就是task control block任务控制块,TCB里包含了该任务的堆栈地址,任务入口,任务优先级(priority),任务信号等与TASK相关的信息,REX允许用户直接操作TCB结构。在这些任务被定义和初始化后并不是立即运行的,而是根据优先级的不同而先后执行的,最高优先级的任务在其就绪之后开始运行,因为优先级是根据软硬件的逻辑关系及任务本身的重要性和运行频率来合理的确定下来的,所以这种抢占式的方式在兼顾公平的同时也体现了高效的特点。在程序上这些是利用best task和current task的概念来实现的:

rex_set_best_task( REX_TASK_LIST_FRONT() );

这也就是一个Scheduler的概念,也就是调度。它在REX中是被作为一个function来实现的:rex_sched()。它不能被APP直接调用,在调用rex_sched()前必须设置全局变量:rex_best_task,它的基本算法可以用下面的一段伪代码表示:

当前任务压栈保存状态,等待再次弹出。

任务之间是需要相互通信的,而且任务之间的通信要比APP之间的通信难的多,这也是前文提到的Web Browser从任务变为APP的原因。Task之间的通信是依靠信号量的,也是通过信号量的设置清除和等待促成了任务之间的切换。

典型的,当mc_task创建一个任务的时候,它首先define一个task,初始化这个task需要的数据后mc等待,然后去执行处于ready态的task中优先级最高的,等待该task初始化完毕后准备开始了,再返回给mc一个回馈信号,注意这里的回馈信号是无所谓哪个信号发出了,也就是有一个task准备就绪了就要返回mc,之后task死循环等待信号,这个信号可以是个cmd信号,可以是个timer信号,也可以是一个start信号。Task在收到该信号后,根据信号的不同来处理这些信号。这样就可一通过不同的信号来控制task的运行了。

在rex中,这些信号是被保存在task的TCB中的,信号量就是一个标志位,每一个signal是一个1bit的二进制数,在32位处理器ARM中也就是最多有32个信号量。每个信号量代表不同的意思。任务可以自定义信号量,可以用rex_wait()这个函数来等待某个信号,同时把自己挂起,task也只有通过这种方式挂起,其他task或者中断可以通过rex_get_sigs(), rex_set_sigs(), rex_clr_sigs(), 来对某一个task的信号操作,当Task A set一个信号给Task B的时候,该任务也会存储一些数据在特定的buffer中,set一个信号会引起任务调度,Task B接收到这个信号从而处于就绪态,一旦Task B的优先级足够高而运行后,Task B就可以从buffer中读取数据,这样就实现了任务之间的通信。信号被存在任务自己的TCB中,从而实现了信号传递的目的性和安全性。

REX也提供了定时器的功能。Timer有两种,一种是clock timer,一种是任务自定义的timer。Clk_timer到时后回调用call back函数,会立即执行想要的操作,而自定义的timer不会这样,它只会置一个信号,执行不执行还要看task的优先级。Timer的自定义可通过rex_set_timer来实现,对timer的操作还有:rex_get_timer, rex_resume_timer, rex_cls_timer, rex_pause_timer, rex_timed_wait. 系统每一个时钟滴答都会去检查这个timer有没有到时,REX维持了一个特别的list来存储timer,timer一旦到期,REX就从list中将timer移除,但并不是删掉,只是REX不知道这个timer的存在了。Timer只能被task创建和所有。特别要注意的是:不能在活跃的timer上调用rex_set_timer。程序的循环定时检测就因为timer的存在,timer实现了操作系统对离散时间上的事件的及时响应。

一个timer到了,或者是一个其它信号的设置都可能引起任务的调度,任务的调度中就不得不提到中断的概念。中断顾名思义,就是打断当前的操作,来进行其它操作,操作系统每隔一段时间就要执行一次中断来检测当前出于就绪态的task中优先级最高的一个是不是当前任务,或者是任务自发的产生中断。也就是调用rex_wait。既然中断会破坏当前任务的运行,但一段代码不能被打断的时候就要执行关中断这个操作,这段代码就叫做临界段代码,当执行完这段代码后,也要立即开中断。假如Task a执行关中断后自愿wait了,那么关中断会被存储,而不会影响下一个执行的任务,当Task A再次运行的时候,关中断的状态又被恢复。关于中断有几点要注意的问题:1.在中断中的代码不要操作的太多;2.尽量不要在中断中使用循环,或者等待;3.在中断的情况下不要改动全局变量,这样可能造成被挂起的任务执行错误;4. clk_tick_isr也产生中断。

在操作系统中一定要考虑互斥和共享资源的问题。如果两个人都要过一条河,但是河上只有一条独木桥,如果两个人都同时占用这个桥那两个人都没法过河,这就涉及到了互斥的概念。REX提供了Critical section and Mutual exclusion的概念,特别的我们注意到的就是临界代码的关中断,来实现互斥。其实在任务之间的资源互斥还可以用信号量的方法来解决。这样就出现了一个问题:假如有三个任务,它们的优先级排列顺序如下:Task A>Task B>Task C,Task C先运行,它占用着Task A的资源,这时候因为Task A得不到资源而一直处于suspend状态,而在Task C运行的过程中,Task B就绪了,系统就会在中断的时候挂起Task C而去运行Task B,这样就出现了优先级反转的问题。解决这种问题的办法就是动态改变优先级,也就是把Task C的优先级提升。REX支持优先级的动态改变,但是这是需要深思熟虑后才能做的,因为优先级都是经过严格定义的,一旦改变可能会引起不可预料的后果。优先级的动态定义是通过优先级继承来实现的也就是Task C继承了Task A的优先级。

REX有较强的存储区保护功能,它把一些重要的信息存储在了NV中。在任务的执行中从NV中读取信息来供任务使用。嵌入式操作系统所处的硬件上一定很小,REX把静态变量都存储在一个区,然后是各个任务所需要的空间,之后是动态变量的存储区,存储区的大小应该是实现被告知程序员的,这样程序员就可以合理的安排所用空间的大小了。一般一个任务的堆栈大小也是确定的,所以在任务中不能使用较大的数组或结构体,因为这样会撑爆该任务所在的栈。

if(rex_best_task == rex_curr_task)

return ;

else if(the system is currently servicing interrupts)

{

rex_curr_task = rex_best_task;

}

rex_curr_task = rex_best_task;

rex_start_task( rex_best_task );

REX系统了解1的更多相关文章

  1. REX系统2

    REX(Real Time Executive)是一个面向嵌入式应用的,简单高效的,抢先式,多任务实时操作系统,支持基于优先级的任务调度算法(支持优先级反转).它提供了任务控制,任务同步,互斥,定时器 ...

  2. REX:EOS资源租赁平台详解

    关键字:REX,资源交易,资源租赁,系统费用,bancor,成熟期,EOS,eosio.system,voting EOSIO 智能合约在v1.6.0版本增加了一个system合约使用的例子,可提供E ...

  3. 2012高校GIS论坛

    江苏省会议中心 南京·钟山宾馆(2012年4月21-22日) 以"突破与提升"为主题的"2012高校GIS论坛"将于4月在南京举行,由南京大学和工程中心共同承办 ...

  4. Verilog学习笔记基本语法篇(十一)········ 常用系统函数

    1)系统任务:$monitor   格式: $monitor(p1,p2,p3...pn); $monitor; $monitoron; $monitoroff; 任务$monitor提供了监控输出列 ...

  5. 使用 SLF4J + LogBack 构建日志系统(转)

    转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...

  6. 架构之ELK日志分析系统

    ELK多种架构及优劣 既然要谈ELK在大数据运维系统中的应用,那么ELK架构就不得不谈.本章节引出四种笔者曾经用过的ELK架构,并讨论各种架构所适合的场景和优劣供大家参考. 先大致介绍ELK组件.EL ...

  7. InChatter系统之本地化

    InChatter现在支持本地化了,其实这个只是很细节的东西,但是咱也是可以走走国际范.哈哈 其实最重要的原因只是想进行一次本地化的开发.这个概念相信大部分人都有,但是在实际项目中真的很少会涉及到,我 ...

  8. 在Openfire上弄一个简单的推送系统

    推送系统 说是推送系统有点大,其实就是一个消息广播功能吧.作用其实也就是由服务端接收到消息然后推送到订阅的客户端. 思路 对于推送最关键的是服务端向客户端发送数据,客户端向服务端订阅自己想要的消息.这 ...

  9. 数据库优化案例——————某市中心医院HIS系统

    记得在自己学习数据库知识的时候特别喜欢看案例,因为优化的手段是容易掌握的,但是整体的优化思想是很难学会的.这也是为什么自己特别喜欢看案例,今天也开始分享自己做的优化案例. 最近一直很忙,博客产出也少的 ...

随机推荐

  1. 状压DP入门详解+题目推荐

    在动态规划的题型中,一般叫什么DP就是怎么DP,状压DP也不例外 所谓状态压缩,一般是通过用01串表示状态,充分利用二进制数的特性,简化计算难度.举个例子,在棋盘上摆放棋子的题目中,我们可以用1表示当 ...

  2. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  3. 【转】器件为什么只听英文Datasheet的话

    浅谈为什么要阅读英文数据手册 ——带你Go Through Datasheet 系列 Unfortunately!从事软硬件(固件)开发的工程师都知道,我们所用的元器件,特别是高端器件和芯片,都是来自 ...

  4. 《Linux内核设计与实现》第3章读书笔记

    第三章 进程管理 一.进程 1.进程就是处于执行期的程序,但并不局限于可执行代码.实际上,进程是正在执行的程序代码的实时结果. 2.执行线程是在进程中活动的对象 每个线程拥有一个独立的计数器.进程栈. ...

  5. (转)教你完全理解IO流里的 read(),read(byte[]),read(byte[],int off,int len)以及write

    背景:对于IO部分,总是感觉很虚,不能很好的理解其中的要义,其实仔细分析,掌握其中的规律,一切都会看起来十分的自然. 1 理解 1.1 从头总结 长期以来,java中的InputStream Outp ...

  6. .Net并行编程系列之三:创建带时间限制(Timeout)的异步任务并取得异步任务的结果

    尝试创建基于MVVM三层架构的异步任务: 场景:View层触发ViewModel层的动作请求,ViewModel层异步的从Model层查询数据,当数据返回或者请求超时时正确更新ViewModel层数据 ...

  7. 利用RAP搭建可视化接口管理平台

    环境:CentOS7 jdk:1.7.0_51 redis:3.2.8 mysql:5.6 tomcat:8.0 安装过程: 依赖组件安装: 安装jdk.redis.mysql.tomcat过程省略. ...

  8. P3355 骑士共存问题

    P3355 骑士共存问题 题目描述 在一个 n*n (n <= 200)个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n ...

  9. tensorflow变量作用域(variable scope)

    举例说明 TensorFlow中的变量一般就是模型的参数.当模型复杂的时候共享变量会无比复杂. 官网给了一个case,当创建两层卷积的过滤器时,每输入一次图片就会创建一次过滤器对应的变量,但是我们希望 ...

  10. LocalDateTime与字符串互转/Date互转/LocalDate互转/指定日期/时间比较

    Java 8中表示日期和时间的类有多个,主要的有: Instant:表示时刻,不直接对应年月日信息,需要通过时区转换 LocalDateTime: 表示与时区无关的日期和时间信息,不直接对应时刻,需要 ...