实时操作系统
E-OS 微机版 1.0
操作手册
前言
现在国内的嵌入系统应用越来越普及,发展很快,层次也不断提高,从 8 位机到 32
位处理器的应用。在产品功能不断提高的同时,为了提高产品的档次和可靠性,嵌入系
统需要操作系统(嵌入式操作系统)的支持。专家预言后 PC 时代是嵌入系统时代,比如
现在的自动化程度比较高的处理器上,可能装有十几片嵌入式处理器。
什么是嵌入式操作系统?
嵌入式操作系统是对实时性要求很强的操作系统,因为很多嵌入系统都是实时应用。
实时性即软件必须对外部和内部时间在适当的时间内产生正确的应答。大多数嵌入式操
作系统都是强占式多任务系统。
为什么需要嵌入式操作系统?
因为一个系统为了很好的完成功能,可能需要几个不同(重要性级别不同)的任务
同时工作,如在一个 TCP 网络通讯中,系统需要随时对接收到的输入包进行解包,又要
对读取的数据进行处理,可能又要发送应用数据,还要提供重发机制。
若用传统的单进程循环对任务进行检测执行可能不能实现,即使实现,也必是一个
应答很慢的系统。并且控制的任务越多,应答时间越慢。同时由于应用程序参与处理器
的分配逻辑,造成软件修改困难、软件难以理解。
嵌入式操作系统根据任务优先级的不同来分配处理器的执行时间,消除了应用程序
对分配逻辑的参与。当一个更重要的任务需要执行时,操作系统负责挂起当前任务,当
重要的任务执行完后,再恢复原先挂起的任务。应答时间是挂起当前任务和恢复优先级
高的任务的时间,基本上在一个固定的时间之内,与执行任务的多少无关,任务可以动
态增加、删除、改变优先级等。
除了管理任务的切换,嵌入式操作系统还提供了象邮箱、消息管道、队列、信号灯、
事件组等任务间的通讯、同步机制,还提供了存储管理、定时器管理等功能。因此方便
了用户在此基础上专心开发自己的应用任务。
这样写成的软件由于是一个一个独立的任务,因此容易理解,修改维护也容易。
嵌入式操作系统的现状
目前嵌入式操作系统在国外还是比较多的,大约有七、八十套,应用也很普及,在
国内比较有影响的有,。并且国外的嵌入式操作系统价格很贵,少则几十万,多则上百万,
当然由于发展早,比较稳定可靠。而国内开发的嵌入式操作系统却很少,因此国内的应
用现状是已经上规模的单位花高价购买了国外的嵌入式操作系统,刚起步的公司则移植
国外代码公开的操作系统,如 LINUX,UCOS 等,但由于 LINUX 不是专为嵌入系统开
发的,也不具有实时性,大量的功能在嵌入系统根本用不上,因此移植不会很成功。而
UCOS 功能太少,根本不能用于大的和功能强的系统,另外实时性也值得考虑。因此国
内急需开发一套功能比较强的嵌入式操作系统。
E-OS 正是基于我国的这些现状而设计的多任务嵌入式实时操作系统,开发策落是在
功能上尽量和国外商品的嵌入式操作系统看齐。
E-OS 的任务调度方式采用强占加时间片轮转方式。优先级高的任务抢先运行,在相
同优先级任务间采用时间片轮转方式,并且每个任务可以规定一个最长执行时间,从而
完全避免了任务死锁的情况发生。
E-OS 任务间的通讯、同步方式有信号、邮箱、消息管道、队列、信号灯、事件组等,
也提供了存储管理(包括分区存储池和可变尺寸存储池管理),定时器管理功能。
在此基础上目前开发了网络通讯模块,支持 TCP、UDP 通讯,可以采用 SOCKET 插
口或文件操作方式。对于设备驱动,提供了设备驱动接口。
整个系统目前在 PC 机上用 BC3.0 调试通过。
但是,刚问世的 E-OS 还有很多不足,需要增加许多功能,如文件系统、图形窗口支
持,支持的网络协议也要丰富,低层的驱动程序也要大大丰富,这样才能满足用户的需
要。但是我想随着支持国产软件发展的用户的参与和支持,E-OS 不断增加功能,会越来
越强大。
第一章 进程管理
E_OS 中没有进程,只有线程,这也是大多数嵌入式操作系统常采取的形式。E_OS
中线程分五种,任务、信号处理程序、高级中断处理线程,低级中断处理线程、系统错
误处理线程。
信号处理程序与其它线程有点不同,每个信号处理程序都有对应的任务,信号处理程序
的执行上下文在对应的任务的堆栈空间之上建立,在该任务接收到另一个线程发来的信
号时,该任务对应的信号处理程序的执行上下文自动建立,并执行,在执行完成后,自
动又恢复原先任务的执行上下文。
任务和高级中断处理线程参与线程调度,都有独立的堆栈空间,在有高级中断处理线程
激活时,高级中断处理线程优先调度执行,并且不允许不挂起,直到执行完成,可以被
优先级更高的高级中断处理线程强占。
低级中断处理线程被中断自动自动触发执行,并且低级中断处理线程没有自己独立的堆
栈空间,在中断发生时当前线程的堆栈空间执行。低级中断处理线程的执行关闭中断,
因此执行时间应尽量短,通常是激活高级中断处理线程,由高级中断处理线程来处理大
量的工作,高级中断处理线程不关闭中断。
系统错误处理线程在发生系统错误时触发执行如堆栈溢出等。
1.1 进程数据结构
任务向量表
struct task_struct *TaskTable[MAX_TASK_NUM];
因为系统中同时有多个任务,为了方便由任务标识号找到对应的任务控制块,又不显著增加系统占
用,E-OS 用任务向量表在任务标识号和任务控制块之间进行一一对应,在系统初始化后,没有创建
任何任务之前,任务向量表的每个向量都为空指针。在创建任务时,从 0 索引开始顺序在向量表中找
到一个空指针位置,该位置索引就为该任务的 ID,并让该位置的向量指向已经分配的任务控制块。
由于每个向量仅占一个指针的位置,因此增大任务数不显著增加系统占用。而有些系统静态分配任务
控制块,系统定义多少最大任务,任务控制块就占用多少系统资源。
但随着任务的不断创建和删除, 任务向量表中的空位置会变的很不规则。为了在任务向量表中的
空位置变的不规则的时候,也能够方便找到空指针位置,系统还把任务向量表中的空槽位组成一个链
表.
struct task_struct *TaskFreeList;
初始时 TaskFreeList 为空指针.每次删除任务都把删除的任务插入该链表的头.在已创建任务数
(包括删除的)达到 MAX_TASK_NUM 时,以后再创建任务就把 TaskFreeList 指向的任务控制块作为创建
任务的控制块,并修改 TaskFreeList 指针使其始终指向自由的任务控制块,直到为空指针为止,这时
表示创建任务数已经达到 MAX_TASK_NUM,已经没有位置可以利用,需要重新定义 MAX_TASK_NUM 系统
参数.
在进程数据结构中最重要的结构是任务控制块 task_struct,每一个进程都用一个任务控制块来表
示。系统利用该结构管理系统中的任务的执行。该结构定义如下:
struct task_struct{
UNSIGNED id; // 任务的 ID
VOID *protect_ptr ; // 指向在该保护结构上挂起线程的头指针
INT8U priority; // 当前优先级
INT8U type;
INT8U status; // 当前状态
INT8U time_slice; // 任务切换时间片
INT16U scheduled; // 已调度次数
UNSIGNED *stack_start; // 指向堆栈开始地址
UNSIGNED *stack_end; // 指向堆栈结束地址
VOID *stack_pointer; // 堆栈指针
struct task_struct *prevrdy;
struct task_struct *nextrdy;
VOID (*entry)(VOID); // 任务入口函数
UNSIGNED argc; // 任务参数个数
VOID *argv; // 参数数组
TIMER_TCB timer_control; // 定时器控制块
VOID (*cleanup)(); // 清除函数
VOID *cleanup_info; // 清除信息
VOID (*signal_handler)(UNSIGNED); //信号处理句柄
UNSIGNED signals; //包含当前信号的信号组
UNSIGNED enabled_signals ; //包含允许信号掩码
VOID *saved_stack_ptr; // 保存的信号处理线程的堆栈指针
UNSIGNED task_timeout; // 当前任务运行最大时间限制
BOOLEAN timer_active; // 定时器的激活标志
};
1 进程 id;
任务的标识号,在创建任务时赋值。系统利用标识号唯一的标识一个任务。该标识号与该任务在
任务向量表中的索引号相同,因此索引号从 0 到 MAX_TASK_NUM-1 之间,系统的大多数与任务有关的
函数都用该标识号来代表要操作的任务。
2 priority; 任务的优先级,在任务创建时规定,在 0 到 255 之间,数目越小优先级越高,因此
priority 为 0 的任务优先级最高。由于该系统调度采用基于任务的优先级强占式,优先级高的任务
可以强占优先级低的任务,因此当前执行的任务总是准备好任务列表中优先级最高的任务。任务的任
务优先级也可以利用函数 SetPriority 动态改变。
3 type 指定线程类型,线程类型可以是 TASK,SIGNAL,HISR,LISR 四种,分别代表系统支持的
四种线程类型
4 status 记录任务的当前状态,随着任务的执行而改变。
任务的状态总是处于 READY、SUSPEND、TERMINATED、 FINISHED 之一
(1) READY 准备好状态,处于该状态的任务可以调度执行。
(2) SUSPEND 挂起状态,处于该状态的任务不参与调度,表示任务强制挂起或正等待某个
资源发生,任务挂起时可以规定一个超时时间,在超时时间到之前,等待的资源还不能
满足或没有主动恢复,任务自动恢复。挂起状态又具体的划分为(PURE_SUSPEND、
SLEEP_SUSPEND、EVENT_SUSPEND)
PURE_SUSPEND 表示任务处于主动挂起状态,处于此状态的任务不等待任何事件发生,
因此只能由用户采用 ResumeService 函数主动恢复。一个例外是也可以被其登记的信号的
发生而唤醒。
SLEEP_SUSPEND 表示任务处于睡眠挂起状态,处于此状态的任务在睡眠时间到时恢复重
新调度。若规定一个无穷睡眠时间,效果等效于处于主动挂起状态。
EVENT_SUSPEND 表示进程在等待队列中正在等待某个事件或资源而处于挂起状态,在
等待的事件发生时或等待的资源有效时,任务恢复。
(3)TERMINATED 终结状态,在利用任务终止函数 TerminateTask 任务就处于该状态。处于该
状态的任务也不参与调度,也不等待任何资源,因此不能用恢复函数恢复调度。唯一可以
评论0