Contiki概要
1. 简述
提到Contiki,当然要从Adam Dunkels的几篇重要论文开始,首要的是《Contiki-a Lightweight Flexible System for Tiny Networked Sensors》,该文说明了作者创作Contiki操作系统的缘由和想要达成的目标,以下仅针对该论文作简要说明。
2. Contiki的目标
从该文看,Adam建立Contiki的首要目的应该是为了大量WSN节点的在线升级,因为在物联网时代,大量的节点由于升级或者bug修复的需要,将不得不在线升级,如何提供尽量小的升级patch而非完整的将很有帮助。同时,可移植性与事件驱动的机制都是Contiki需要考虑的。
3. Contiki的组成
按照Adam的设计,Contiki系统由以下四个部分组成:
- 内核.考虑到WSN节点的特殊性,内核未定义硬件的抽象层,也没有内存的保护机制,进程间以及进程/设备驱动直接与硬件通信;
- 库
- 程序装载器
- 进程.进程是Contiki中重要的概念,可以是应用程序或者服务(比如网络协议)。无论是应用程序或者服务,可以在运行时被替换回应上面提到的Contiki设计的目的。进程由一个事件处理函数或者可选的poll处理函数定义poll处理函数是?,之间的通信通过发送event进行。
同样,为了能达到运行时升级程序的目的,Contiki在ROM或RAM中分为两个部分:核心部分与装载程序部分,如图1所示。一般情况下,程序首先存储在ROM中,然后再加载到内存里。
注:根据该文的说明,个人的理解是Contiki首要的目的是实现在线升级或bug修正,否则已有的TinyOS等系统已经很成熟了,并没有必要再额外再开发一个操作系统。所以为了透彻理解Contiki,有可能有必要花时间去了解其loader目录下的源代码部分。
4. 内核架构
内核部分已经有很多文章进行分析,一般都是从hello-world的例子逐步展开相关的宏定义来理解进程、事件等的机制,可以理解细节但不容易抓住总貌。Adm文中开宗明义:"The Contiki kernel consists of a lightweight event scheduler that dispatches events to running processes and periodically calls processes’ polling handlers",所以Contiki的核心是事件调度器,事件调度器发送事件给进程,并且定期调用进程的poll处理器,由此而带出进程、定时器等等。程序的运行由内核或者polling机制发送的事件触发。事件一旦触发处理,内核无法抢占,必须执行完成。
内核支持同步与异步两种事件目前分析过的代码看到的主要是异步事件,同步事件要再分析,而且已经有了polling机制,为何还需要同步机制??,异步事件被分配到事件队列中,然后被依次处理,polling机制类似于高优先级的异步事件,有polling标识的会被优先处理。这部分分析很多了,可以参考"Contiki初步"中的参考资料。
Contiki内核用一个共享栈处理所有进程的运行,也就是结合C语言的__LINE__、switch/case以及static变量特性实现的现场保存和恢复,这部分同样已经被其它很多文章分析了。不过Adm提了一句"The use of asynchronous events reduce stack space requirements as the stack is rewound between each invocation of event handlers",后面的好理解,前面的说明莫非仅仅异步事件才用到共享栈?当然,这里也带出Contiki编程中的一些注意事项,具体可以参考"Contiki初步"中的参考说明。
Contiki的可装载程序通过以下两个机制实现:
- 运行时重定位函数
- 包含重定位信息的二进制格式(elf)
程序装载过程如下:
- 分配内存,如果不够,则失败;
- 调用程序的初始化函数,该初始化函数可以替换或启动多个进程
无线传感器网络中,能量控制当然是其中非常重要的一环,Adm认为其中包含应用与网络协议。尤其后者分析非常多,Contiki的思想在于暴露部分关键数据,由应用(或网络协议)开发者根据需要进行节点休眠节省能量比如事件队列大小。
5. 服务
服务是实现了其它进程可以调用的函数的进程,类似于动态链接库。在进程调用服务时,服务通过文本检索,而每个服务有版本号,避免替换时版本不匹配。具体可以参考下图:
服务是Contiki实现动态升级的重要部分,在一个进程调用了服务后,服务的进程id就作为其唯一标识,因此Contiki提供了特殊的机制来替换进程并保持原有的进程ID这部分没有研究过。在服务替换以后,内核会发送一个特殊事件通知运行版本的服务,该服务必须在收到事件后将自己从系统中移除掉。新旧服务替换时,有可能需要将旧服务的一些状态信息转移到新服务,Contiki也提供了相关的机制(一个指针),并且用版本号标识状态信息,以免出现不兼容的情况。
注:网络协议是一种典型的服务,但服务部分替换运作机制分析文档甚少,需要再研读相关代码。
6. 库
为了保持系统的精简,Contiki内核仅仅提供最基本的CPU多路处理和事件处理功能,其它部分都以库的方式实现,可以通过程序静态链接核心库、可装载程序库以及动态链接服务的方式使用库。通过这些方式,可以实现映像最小化。
7. 其它
文中还提到了通信协议栈以及抢占式多线程的设计思路,前者是无线传感器网络的核心,Contiki提供的rime和uIP使用了Contiki灵活的网络协议实现架构,此部分另作他文描述。而抢占式多线程,主要是对mt_yield(), mt_post(), mt_wait(), mt_exit(), mt_start()以及mt_exec()等API的理解,在此不做赘述。
8. 讨论及结论
除了Contiki能实现的功能以外(如多跳路由、移动检测),Adm归结了Contiki通过空中接口在线编程、其本身映像大小、抢占式处理的CPU利用以及可移植性等方面的优势,这些部分在他成文时可能不一定明显,但放在现在已经不成为太大的问题了。