作为 ADEOS 的开发者(或是其他操作系统的开发者),你需要知道如何创建和使用任务。就像别的抽象数据结构,Task 类有自己的成员函数。ADEOS的的任务接口比别的大多数操作系统要简单一些,因为它只是创建一个新的Task 对象。一旦创建,ADEOS 任务继续在系统中存在,直到相关的函数返回。当然,这也许永远不会发生(意即ADEOS 任务也许永远不会结束),但是,如果一旦发生了,那么该任务就会被操作系统删除掉。Task 的构造函数如下所示。调用者通过构造函数的参数分配一个函数,一个权限值,和一个可选择的新任务的堆栈大小。第一个参数,fUnCtion,是一个指向C/C++语言或汇编语言的函数指针,该函数是要在新任务的上下文环境中运行的。该函数不需要任何输人参数,也不返回任何结果。第二个参数P,是一个单字节的整数(从1 到255),代表了任务的权限级别,这个权限级别是与别的任务相对而言的,在
tb任务调度器选择新的任务运行的时候会用到(p 的值越大,表示权限越高)。
TaskId Task::nextId = 0
/**************************************************************
*
* Method : Task()
*
* Description : Create a new task and initialize its state.
*
* Notes :
*
* Returns :
*
**************************************************************/
Task:Task(void (*function)(), Priority p, int stackSize)
{
stackSize /= sizeof(int); //Convert bytes to words.
enterCS(); //Critical Section Begin
//
// Initialize the task-specific data.
//
if = Task::nextId++;
state = Ready;
priority = p;
entryPoint = function;
pStack = new int[stackSize];
pNext = NULL;
//
// Initialize the processor context.
//
contextInit(&context, run, this, pStack + stackSize);
//
// Insert the task into the ready list.
//
os.readyList.insert(this);
os.schedule(); // Scheduling Point
exitCS(); // Critical Section End
} /* Task() */
注意这个例程的功能块被两个函数 enterCS()和exitCS()的调用包围。在这些调用之间的代码块叫作
tb临界区(critical section)。临界区是一个程序必须完整执行的一部分。也就是说,组成这一个部分的指令必须没有中断地按照顺序执行。因为中断可能随时发生,保证不受到中断的唯一办法就是在执行关键区期间禁止中断。因此在关键区的开始调用enterCS 以保存中断的允许状态以及禁止进一步的中断。在关键区尾部调用exitCS 以恢复前面保存的中断调用。我们会看到在下面每一个例程中都应用了同样的技巧。
在前面代码中,有几个在构造函数里调用的其他例程,但是在这里我没有空间列出。它们是contextInit()和os.readyList.insert()例程。例程contextInit()为任务建立了初始的设备场景。这个例程必定是处理器专用的,因此是用汇编语言写的。
contextInit()有四个参数。第一个是一个指向待初始比的设备场景数据结构指针。第二个是一个指向启动函数的指针。这是一个特殊的ADEOS 函数,叫作run(),它被用来启动一个任务,并且如果以后相关的函数退出了,它被用来做其后的清理工作。第三个参数是一个指向新任务对象的指针。这个参数被传递给run(),因此相关的任务就能够被启动。第四个和最后一个参数是指向新任务栈的指针。
另一个函数调用是 os.readyList.insert()。这个函数把新任务加入到操作系统内部的就绪任务列表中。readyList 是一个TaskList 类型的对象。这个类是那些具有insert()和remove()两个方法的任务(按照优先级排序)的链表。感兴趣的读者如果想知道这些函数是如何实现的就应该下载和研究其ADEOS 的源代码。你将在下面的讨论中了解到更多有关就绪列表的问题。