嵌入式操作系统NUT/OS的原理和实现

时间:2022-09-09 10:28:00

嵌入式操作系统NUT/OS的原理和实现

摘要:NUT/OS是一个实时的嵌入式操作系统,源码完全公开且免费。该文通过研究其内核可以更好的理解嵌入式操作系统的实现原理,重点分析了NUT/OS系统中的任务调度机制,时间管理机制,任务管理机制以及内存管理机制的实现原理,并指出NUT/OS在移植过程中面临的困难。

关键词:实时操作系统;NUT/OS;任务调度;内存管理

中图分类号:TP316文献标识码:A 文章编号:1009-3044(2009)36-10371-03

Principle and Implementation of NUT/OS

YANG Xiao-ping

(Faculty of Computer, Guangdong University of Technology, Guangzhou 510006, China)

Abstract: As a free and open-source embeded operate system,and because of its outstanding networking,NUT/OS is concerned greatly.this paper analyzes the architeture as well as principle and mechanism of NUT/OS’s kernel,and points out its disadvantage in the transparent.

Key words: RTOS; NUT/OS; task schedule; memory management

嵌入式实时操作系统(Real-Time Operating System)在目前的嵌入式应用中越来越显示出其重要意义。采用嵌入式实时操作系统可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。因而研究嵌入式操作系统内核的原理及其实现,使我们在实际的开发中选择和应用操作系统时更加主动,更加灵活。

目前一些比较有名的免费的、源码开放的操作系统有μClinux、μC/OS-Ⅱ和FreeRTOS等。NUT/OS作为一个网络功能突出的嵌入式操作系统,在当今众多嵌入式设备都需要接入网络的情况下,其应用前景广阔。NUT/OS是Ethernut项目组针对Ethernut开发板设计、开发的一套实时、多任务的嵌入式操作系统,其源代码是完全公开免费的。

1 NUT/OS层次结构

针对8位MCU特点,NUT/OS很紧凑的实现了操作系统功能,核心具有任务调度管理,文件管理,内存管理,事件管理功能,功能支持FAT、ROMEFS文件系统,网络通讯以及设备管理。图1是NUT/OS操作系统功能示意图。

NUT/OS内核支持优先级调度算法,CPU总是让处于就绪态的,优先级最高的任务最先运行。NUT/OS内核同时支持轮换调度算法,系统允许不同的任务可以使用相同的优先级,在没有最高优先级任务就绪的情况下,相同优先级的任务共享CPU时间。

2 NUT/OS操作系统的原理和实现

2.1 任务调度管理

嵌入式实时操作系统的一个重要概念就是任务调度。在抢占式内核中,优先级高的任务一旦就绪就能抢占优先级低的任务的CPU使用权,这样就提高了系统的实时响应能力。NUT/OS中没有对任务的数量加以限制,任务优先级数的范围相对μC/OS-Ⅱ来说也很大,优先级可以从0到254;同时NUT/OS支持优先权调度算法和轮转调度算法,因此NUT/OS采用链表的方法进行任务的调度。系统定义了下面的链表和参数:

NUTTHREADINFO * nutThreadList; //全部线程列表

NUTTHREADINFO * runQueue;//全部就绪态按优先级排队的线程列表

NUTTHREADINFO * runningThread;//当前正在运行的线程

NUT/OS总是运行就绪任务中优先级最高的那一个,系统运行中,当有优先级更高的任务插入到优先级就绪任务队列时,系统就调用NutThreadSwitch()进行任务切换。调度只会在如下情况下发生:

1)运行中的进程受阻或自动放弃CPU;

2)运行中的进程“自杀”或“被杀”;

3)运行中的进程唤醒某个线程;

4)中断服务子程序结束时唤醒其它进程;

5)新线程创建时。

2.2 任务管理的实现

任务管理包括如何在用户的应用程序中建立任务、删除任务、设定任务优先级、挂起和恢复任务,以及获得任务的相关信息等。NUT/OS中每个任务对应一个任务控制块,系统通过任务控制块来感知和管理一个任务。任务控制块的结构定义如下:

struct _NUTTHREADINFO {

NUTTHREADINFO *td_next;

//指向全部线程列表中的下一个

NUTTHREADINFO *td_qnxt;

//全部就绪态按优先级排队的线程列表

volatile unsigned int td_qpec; //阻塞事件计数器

char td_name[9]; //线程的名字

uint8_t td_state;//线程的状态

uintptr_t td_sp; //线程的堆栈指针

uint8_t td_priority;//线程的优先级

uint8_t *td_memory;

//指向堆栈中已使用的堆栈内存

HANDLE td_timer;//事件定时器

volatile HANDLE td_queue;

//等待队列的根入口地址

};

可以通过调用下面的这个函数来创建一个线程:

HANDLE NutThreadCreate(char *name, void (*fn) (void *), void *arg, size_t stackSize);

创建线程的过程实际上就是从堆栈空间申请一个放置线程控制块的空间,若申请成功,则建立线程控制块并完成线程控制块的初始化。接着将新创建的任务插入到就绪任务队列,若当前任务的优先级最高且任务调度程序已经运行,则进行上下文切换。NutThreadCreate()成功返回时,将返回一个句柄,指向新任务控制块的数据结构。

NUT/OS中的任务有4种状态,分别是:睡眠态,等待态,就绪态和运行态。任务在系统中一定处于这4种状态中的一种。在系统内核管理下,各个任务可以按照图2所示进行状态转换。在内核NUT/OS中,为了任务调度的需要,处于运行态的任务的任务控制块并不从就绪任务队列中删除,仍位于就绪队列的首部。一旦发生中断,运行态任务就进入就绪态。任务因等待某种资源、信号或者消息而无法继续运行时就转入等待态。出入等待态的任务获得需要的资源后,重新进入就绪态。睡眠态是指任务驻留在程序空间没有交由内核来管理。

当任务运行完之后,可以自行删除。与μC/OS-Ⅱ不同的是,NUT/OS删除任务时,先调用系统提供的函数NutThreadExit(),将该任务的优先级数设为255,任务从调度队列中移出。此时任务的代码和占用的空间并没有被删除, NUT/OS只是不在理会这个任务,该任务也不能再被调度执行。当空闲任务运行时,调用NutThreadDestroy(),将该任务占有的内存空间反还给系统。

2.3 时间管理的实现

时钟管理也是系统内核的一个重要功能,它为用户提供任务定时等系统服务。内核NUT/OS通过定时器数据结构NUTTIMERINFO和一个定时队列NUTTIMERLIST来实现定时服务。定时队列中,链接的基本结构为定时器数据结构。全局变量NUTTIMERLIST是定时队列的头指针。用户定义并使用的定时器,在时间期限到来之前按定时的长短顺序排放在定时队列中,处在定时队列后面定时器要等到其前面的定时器到期之后才能开始计时。

时钟的节拍式中断是任务实现超时或定时功能的依据.每发生一个时钟节拍,函数NutTimer0Intr()首先将定时队列上的第一个NUTTIMERINFO的时钟节拍tn_ticks_left减1,并判断该值是否为0.如果为0,说明该定时器的定时时间到期,则内核将该定时器的数据结构从定时队列上删除,同时将指向该定时器的任务从等待态转为就绪态;接着继续处理该队列上位于队首的下一个定时器数据结构NUTTIMERINFO,直到处理完该队列上所有到期的任务。如果tn_ticks_left不为0,说明没有定时器到期,则该函数不做任何处理直接结束。

NUT/OS提供的比较典型的时间管理函数NutDelay()和NutSleep(),它们都可以实现将一个任务延时一段时间的功能。但是使用NutSleep()只能将当前线程挂起整数个节拍的时间,时间只是时钟节拍的整数倍,该函数不能实现精确延时。NutDelay()可以实现精确延时,它不会挂起当前线程,即当前线程仍然处于运行态。除非有更高优先级线程转入就绪态,否则仍然拥有CPU的控制权。

2.4 内存管理的实现

每当任务、队列、信号量创建时,都要向系统申请分配一定的内存空间。合理且灵活的内存管理不仅可以保证系统正确高效的运行,同时还可以提高系统可靠性。

NUT/OS采用堆的形式动态管理内存。堆中包含了系统的所有空闲内存块,NUT/OS定义了一个全局指针heapFreeList指向堆入口,各个空闲块按照地址排序。空闲块的数据结构在系统中是这样定义的:

typedef struct _HEAPNODE{

size_t hn_size;

//该空闲节点的大小

struct _HEAPNODE *hn_next;

//指向下一个空闲节点的指针

}HEAPNODE;

NUT/OS采用最佳拟合分配策略。当应用程序申请一个内存空间时,系统根据申请的大小搜索空闲链表,找到满足要求的最小空闲块。为了提高内存的使用效率,在空闲内存块比请求的空间大并且两者之差大于某个设定的阈值的情况下,系统将该空闲内存块一分为二,一块用于满足用户申请要求,另一块作为新的空闲内存块继续留在空闲块链表中。空间释放时,查找空闲块块链表,按照地址先后顺序插入到链表中,当待插入的节点与链表中的空闲节点在地址上是前后连续时,则合并成一个空闲节点。系统中用NutHeapAlloc()分配的空间,用户需要显式的调用NutHeapFree()释放,否则会造成内存泄漏。

μC/OS-Ⅱ提供的内存管理机制是把连续的大块的内存按照分区来管理,每个分区中包含整数个大小相同的块。由于每个分区的大小相同,即使频繁的申请和释放内存块也不会产生内存碎片,但是内存利用率不高。NUT/OS的内存管理策略,能够使内存块得到很好的使用。

3 NUT/OS的移植

μC/OS-Ⅱ自1992年以来,已经被移植到几乎所有嵌入式应用类CPU上,许多行业都有成功应用该实时内核的实例。NUT/OS作为一个网络功能突出的嵌入式操作系统,其应用前景广阔。但是由于NUT/OS在开发时是针对特定的硬件环境进行的,包括网络适配器的型号也是固定的,另外对硬件系统使用的时钟也有特定的要求,因而在非Ethernut开发板上移植NUT/OS面临着很多困难。移植过程中涉及到很多需要修改系统底层代码的地方,其中最重要的是硬件启动代码的修改和审查,因为NUT/OS的网络配置部分也在进入main()之前完成,这部分代码如果需要硬件应答并由此阻塞则无法启动操作系统。写作本文的目的也是在于此,通过对系统内核的原理及其实现的分析,加深对其过程及各种机制的理解,为我们在实际的(不同于Ethernut开发板)硬件环境下移植和应用NUT/OS提供帮助。

4 结束语

随着以太网的使用日益普遍,嵌入式设备也必将走入网络化,为此需要一种简单实用的网络接入方案。运行于8位MCU上的NUT/OS实时系统提供了TCP/IP协议栈的支持,可以通过UART拨号方式或以太网接入网络。NUT/OS的开发小组提供了操作系统源码,并且处于对系统的不断完善中。硬件版本和软件版本也一直在更新,相信国内将有很多人来学习和使用这项新技术,NUT/OS操作系统的应用范围也会越来越宽。

参考文献:

[1] 许庆春,吴光敏.Nut/OS和μC/OS-II的实时调度算法比较[J].单片机及嵌入式系统应用,2006(5).

[2] 许庆春,吴光敏.Ethernut技术的研究与应用[D].昆明:昆明理工大学,2007.

[3] 闫丽,牛连强.Atmega128微控制器嵌入式内核的分析与改进[D].沈阳:沈阳工业大学,2005.

[4] Welcome to the Ethernut Project[EB/OL].www.ethernut.de.

[5] 杨云,张勇.基于ARM7的μC/OS-Ⅱ移植分析与实现[J].计算机工程与设计,2009(3):539-541.

[6] 杨科峰,邵时.嵌入式实时系统调度策略[J].计算机应用研究,2000(80):31.

[7] 何福贵,侯义斌,李辉.嵌入式操作系统调度机制的研究[J].计算机应用研究,2009(26).

[8] 高峰.嵌入式实时多任务微内核核心研究[D].成都:电子科技大学,2001.

上一篇:基于Camshift算法的运动目标检测 下一篇:低端交换机ARP入侵检测的策略及实施