Contiki——为微传感器网络而生的轻量级的灵活的操作系统
Posted tidyjiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Contiki——为微传感器网络而生的轻量级的灵活的操作系统相关的知识,希望对你有一定的参考价值。
说明:本系列文章翻译自Contiki之父Adam Dunkels经典论文,版权归原作者所有。
Contiki是由Adam Dunkels及其团队开发的系统,研读其论文是对深入理解Contiki系统的最佳资料。
-----------------------------------------------------------------------------------------------------------------------------------------------------------摘要:
无线传感器网络由大量微小的联网可通信设备组成。对于大规模网络而言,动态地下载代码到网络中是极其重要的。在本论文中,我们描述了一个支持动态地加载、替换个人储蓄和服务的轻量级操作系统——Contiki。Contiki基于事件驱动(event-driven)内核,并提供可选的抢占式多线程。在一个资源受限的环境中,Contiki能做到保持基础系统轻量、紧凑的同时,还可以灵活地动态加载和卸载程序和服务。
1.介绍
无线传感器网络由大量具有无线通信能力的微传感器设备组成。这些传感器设备可以自治地构成网络并传输数据。通常情况下,这些传感器设备是资源受限的。板载电池或者太阳能面板只能提供有限的电源供应。此外,微小的尺寸和低廉的价格也限制着系统的复杂性。典型的传感器的配置包括8位微控制器、大约100kb的代码存储空间和小雨20kb的RAM。根据摩尔定律,这些设备在将来会越来越小、越来越廉价。尽管这意味着传感器网络可以被扩展到更大的范围,但却不一定说明相关资源会受到更小的限制。
作为一个为传感器节点设计操作系统的设计者连说,其面临的挑战在于找到一个轻量级的机制和抽象,以在资源受限的设备上提供足够丰富的执行环境。我们已经开发了Contiki——针对资源受限环境而开发的操作系统。Contiki提供了个人程序和服务动态加载、卸载的功能,其内核基于时间驱动(event-driven),并支持抢占式多线程机制。哪些明确需要多线程的程序将被链接为一个库,从而实现可抢占式多线程。Contiki由C语言实现,已被移植到许多微处理器架构,包括TI MSP430、Ateml AVR。我们目前将Contiki运行在ESB平台[5]。ESB使用的微处理器是MSP430,带有2kbRAM,60kbROM,运行在1MHz。这个微处理器可以可选地重烧部分片上flash存储。
本篇论文的贡献主要在两个方面。第一是灵活性。一个资源受限传感器设备之上可加载程序和服务。第二个通用性。抢占式多线程不必再内核最底层实现,而是构建于事件驱动内核顶层作为应用程序库。这允许基于线程的程序运行在基于事件的内核之上,减少系统各部分重入带来的开支、栈空间。
1.1运行时下载代码
我们期望无线传感器网络是大规模的,在每个网络里由成百上千,甚至成千上万的节点。当为这样的大规模传感器网络开发软件时,动态地下载程序代码到网络里就显得尤为重要。此外,在网络运行期间,可能会对其打补丁[9]。一般情况下,单独用人去收集和重新烧写所有的传感器设备是不可行的。事实上,目前已有很多种方法可以将代码分发到无线传感器网络中。对于这些方法,由于通信将占用大部分有效节点能源,所以减少发送到网络中的字节数是关键。大多数用于嵌入式的操作系统都需要编译、下载一个包含完整系统的二进制镜像到设备中。这个二进制镜像包括操作系统、系统库和运行在系统之上的实际应用程序。而与此不同的是,Contiki允许在运行期间加载、卸载个人应用程序和服务。大多数情况下,应用程序远远小于整个系统,因此在通过网络传输时Contiki需要更少的能量。
1.2可移植性
随着不同的传感器设备平台的增加,我们需要一个可以在不用硬件平台移植的通用软件基础架构。当前有效的传感器平台上都载有完全不同的配置。由于应用程序相关的特性,我们期望着部分在将来不会改变。在今天,平台间的统一不变的特性只有一个——不使用段机制或者内存保护机制的CPU架构。在这种架构下,程序代码被存放于可重新编程的ROM,程序数据被存放于RAM。我们设计了Contiki操作系统,其提供CPU多线程抽象(且是唯一的抽象),并支持程序和服务的可加载性。考虑到传感器网络中应用的相关特性,我们认为其他抽象被设计为库或者服务、提供动态机制更合适
1.3事件驱动系统
在内存严重受限的环境中,多线程模型的相关操作占据了大部分的系统内存资源。因为每一个线程都有自己的栈,并且由于通常很难提前知道一个线程需要多大的栈空间,所以系统给线程预分配栈是总是足够多的。当线程被创建时,需要为每个栈分配内存,栈中的内存只能被对应线程使用,不能被当前运行的多个线程共享。此外,线程并发模型需要锁机制来保护可以修改动态资源的线程。为了在不为每个线程分配栈、提供锁机制的同时依然可以提供并发服务,我们使用了事件驱动机制。在事件驱动系统中,进程以事件操作的方式实现。由于一个事件操作不能被阻塞,所有的进程可以使用相同的栈,从而可以在进程间有效地实现稀缺的内存资源的共享。与此同时,由于两个事件操作从不并发地运行,一般情况下锁机制也不需要了。
尽管事件驱动系统在很多种传感器网络应用中都能很好的工作,但是依然存在问题——程序员很难去管理状态驱动编程模型,换句话说,不是所有的程序都可以很方便地使用状态机来描述,比如密码学中的评估算法时间长度。通常,在标准的CPU平台下,这需要几秒钟的时间。在一个纯粹的事件驱动操作系统中,时间长度计算完全独占CPU,使系统不能够响应外部时间。如果操作系统基于可抢占式的多线程模型,这将不是问题,因为时间长度计算能被抢占。
为了结合时间驱动和可抢占式线程,Contiki使用了一个混合模型:系统基于时间驱动内核,而将可抢占式多线程以可选应用库的形式实现,在程序需要它时才被链接。
本论文剩下的部分以如下的形式组织:第2章回顾相关的工作,第3章描述Contiki系统的框架,第4章描述Contiki内核的设计,第5章描述Contiki服务的概念,第6、7章描述Contiki如何处理库、如何处理通信支持,第8章描述可抢占式多线程的实现,第9章描述我们使用该系统的经验,最后,第10章作总结。
2.相关工作
TinyOS[15]应该是针对指定应用和受限传感器设备而开发的最早的操作系统。TinyOS也是基于轻量级的事件机制,所有的程序执行都是在一个从运行到结束任务里执行。TinyOS使用了一个指定的类型语言来完成小组件[12]系统。而这些组件被静态地链接到内核中。链接后,就很难修改系统了[17]。相反地,Contiki提供一个动态结构,允许程序和驱动在运行时无需重新链接就被替换。为了给TinyOS提供运行时重编程功能,Levis和Culler为TinyOS设备开发了一个虚拟机——Mate[17]。这个虚拟机为了典型传感器网络应用而单独设计的。很相似地,MagneOS操作系统[7]使用了java虚拟机来将应用分发到传感器网络。使用虚拟机而不适用本地机器代码的好处是虚拟机代码可以写得很小,在传输代码到网络中时可以减小能量消耗。但是其缺点是增加了解释代码的能量消耗,因为对于长期运行的程序而言,在传输二进制代码时节省的能量将在执行代码时被消耗。Contiki程序使用本地代码,因此可以被适用于各种类型的程序,包括不丢失执行效率的底层设备驱动。SensorWare[8]提供了一个针对可编程传感器的抽象脚本语言,但是他们的目标平台不是像我们这种资源受限的平台。相似的,EmStar[3]环境被设计用于资源更少的受限系统。Reijers和Langendoen[21]使用一个补丁语言去小改处于运行的系统的二进制镜像,这在所有节点运行相同二进制代码的网络中是有效的,但是一旦有一点点不同的程序或者程序的版本不同时就变得特别复杂。
Mantio操作系统[3]使用传统的可抢占式多线程模型操作。通过下载程序镜像到EEPROM,再从EEPROM烧写到flash ROM, Mantio既支持重新编程完整的操作系统,也支持重新烧写部分存储空间。由于多线程的理论,每个Mantis程序必须从系统堆分配栈空间,必须使用锁机制以实现共享变量互斥。相反地,Contiki由于使用基于事件的、没有抢占的调度器,依次避免了多栈分配和锁机制。可抢占式多线程以库的方式提供,当需要的时候才被链接到程序。
Contiki中的可抢占式多线程与fibers[4]类似。轻量级的fibers有Welsh和Mainland[23]实现。余轻量级的fibers不同的是,Contiki不会限制当前线程数量的最大值——2。此外,不像fibers那样,Contiki中的线程支持可抢占式。
与Exokernel[11]和Nemesis[16]类似,Contiki尽量减少抽象的数量,以保持内核尺寸的最小化。抽象以库的形式实现,并且几乎有用下层硬件的完全访问权限。Exokernel追求性能、Nemesis追求服务质量,Contiki追求减小尺寸、维持灵活。与Exokernel不同的是,Contiki不支持保护机制,因为Contiki的硬件在设计时就不支持内存保护。
3.系统概述
一个运行的Contiki系统由内核、库、程序加载器和一系列进程组成。进程可能是应用程序或者服务,服务为多个进程提供功能。所有的进程,包括应用程序和服务,可以在运行时动态加载。进程间通信总是通过内核进行的,但是内核不提供邮件抽象层,而让设备驱动、应用直接与硬件通信。一个进程(process)有一个事件处理函数(event hander)或者可选的轮询处理函数(poll hander function)定义。进程的状态保存在进程的私有内存中,内核中只有一个指向该状态的指针。在ESB平台[5],进程状态由23字节组成。所有的进程共享相同的地址空间,而不是运行在不同的保护域。进程间通过邮差事件(posting events)通信。