Description: This series of articles is translated from the Contiki's father Adam Dunkels Classic thesis, the copyright belongs to the original author.
Contiki, a system developed by Adam Dunkels and his team, studied his paper as the best information for an in-depth understanding of the Contiki system.
Contiki Classic Thesis Translation--index catalogue
--------------------------------------------------------------------------------------------------------------- --------------------------------------------
Summary:
Wireless sensor networks consist of a large number of tiny networked communication devices. For large-scale networks, it is extremely important to dynamically download code into the network. In this paper, we describe a lightweight operating system--contiki that supports the dynamic loading and replacement of personal savings and services. The Contiki is based on the event-driven (Event-driven) kernel and provides optional preemptive multithreading. In a resource-constrained environment, Contiki can keep the underlying system lightweight and compact while providing the flexibility to dynamically load and unload programs and services.
1. Introduction
Wireless sensor networks consist of a large number of micro-sensor devices with wireless communication capability. These sensor devices can autonomously compose networks and transmit data. Typically, these sensor devices are resource-constrained. Onboard batteries or solar panels can only provide limited power supply. In addition, the small size and low price also limit the complexity of the system. Typical sensor configurations include 8-bit microcontrollers, approximately 100kb of code storage space, and light rain 20kb of RAM. According to Moore's law, these devices will grow smaller and cheaper in the future. Although this means that the sensor network can be extended to a larger extent, it does not necessarily mean that the resources involved will be subject to a smaller limit.
As a designer for designing operating systems for sensor nodes, the challenge is to find a lightweight mechanism and abstraction to provide a sufficiently rich execution environment on resource-constrained devices. We have developed an operating system contiki--for resource-constrained environments. Contiki provides the ability to dynamically load and unload personal programs and services, its kernel-based time-driven (Event-driven), and support for preemptive multithreaded mechanisms. Programs that explicitly require multi-threading will be linked to a library, which enables preemptive multithreading.
Contiki is implemented by the C language and has been ported to many microprocessor architectures, including Ti MSP430, Ateml AVR. We are currently running Contiki on the ESB platform [5]. The microprocessor used by the ESB is MSP430, with 2kbram,60kbrom, running at 1MHz. This microprocessor can optionally re-burn some of the on-chip flash storage.
The contribution of this paper is mainly in two aspects. The first is flexibility. A resource-constrained sensor device that can load programs and services. The second versatility. Preemptive multithreading does not have to be implemented at the lowest level of the kernel, but is built on top of the event-driven kernel as an application library. This allows the thread-based program to run on the event-based kernel, reducing the amount of overhead and stack space that comes with the re-entry of each part of the system.
1.1 Runtime download Code We expect wireless sensor networks to be large-scale, in each network by hundreds or even thousands of nodes. When developing software for such a large-scale sensor network, it is particularly important to dynamically download the program code into the network. In addition, [9] may be patched while the network is running. In general, it is not feasible for individual personnel to collect and re-burn all sensor devices. In fact, there are many ways to distribute code to wireless sensor networks. For these methods, reducing the number of bytes sent to the network is critical since communication consumes most of the active node energy.
Most embedded operating systems need to compile and download a binary image containing the full system into the device. This binary image includes the operating system, the system library, and the actual application running on the system. Unlike this, Contiki allows the loading and unloading of personal applications and services during runtime. In most cases, the application is much smaller than the entire system, so contiki requires less energy when it travels over the network.
1.2 Portability
With the addition of different sensor device platforms, we need a common software infrastructure that can be ported without a hardware platform. The current active sensor platform contains a completely different configuration. Due to application-related features, we expect that parts will not change in the future. Today, there is only one unified invariant between platforms-CPU architectures that do not use a segment mechanism or a memory-protection mechanism. In this architecture, the program code is stored in a programmable ROM, and the program data is stored in RAM. We designed the Contiki operating system, which provides CPU multithreading abstraction (and is the only abstraction), and supports the loadable nature of programs and services. Considering the relevant characteristics of the application in the sensor network, we think that other abstractions are designed as libraries or services and provide a more appropriate dynamic mechanism.
1.3 Event-driven system in the memory severely limited environment, the multithreading model's related operation occupies the most system memory resources. Because each thread has its own stack, and because it is often difficult to know in advance how much stack space a thread needs, it is always enough for the system to pre-allocate the stack to the thread. When a thread is created, it needs to allocate memory for each stack, and the memory in the stack can only be used by the corresponding thread and cannot be shared by multiple threads that are currently running. In addition, the threading concurrency model requires a lock mechanism to protect threads that can modify dynamic resources.
To provide concurrent services while not allocating stacks for each thread, providing a lock mechanism, we used an event-driven mechanism. In an event-driven system, a process is implemented as an event operation. Because an event operation cannot be blocked, all processes can use the same stack, allowing the sharing of scarce memory resources to be effectively implemented across processes. At the same time, because two event operations never run concurrently, the lock mechanism is not required in general.
Although event-driven systems work well in many sensor network applications, there are still problems-programmers struggle to manage state-driven programming models, in other words, not all programs can be easily described using state machines, such as the length of the evaluation algorithm in cryptography. Typically, this takes a few seconds under the standard CPU platform. In a purely event-driven operating system, the time-length calculation is completely exclusive to the CPU, making the system unresponsive to external time. This is not an issue if the operating system is based on a preemptive multithreaded model, because time-length calculations can be preempted.
To combine time-driven and preemptive threading, Contiki uses a hybrid model: The system is based on the time-driven kernel, and the preemptive multithreading is implemented in the form of an optional library, which is linked only when the program needs it.
The remainder of this paper is organized in the following form: The 2nd chapter reviews the related work, the 3rd chapter describes the framework of the Contiki system, the 4th chapter describes the design of the Contiki kernel, the 5th chapter describes the concept of Contiki service, 6th, 7 chapters describe Contiki How to handle the library, how to handle communication support , the 8th chapter describes the realization of the preemptive multithreading, the 9th Chapter describes our experience in using the system, and finally, the 10th chapter summarizes.
2. Related work tinyos[15] should be the earliest operating system developed for the specified application and limited sensor devices. TinyOS is also based on a lightweight event mechanism, where all program execution is performed in one run-to-end task. TinyOS uses a specified type language to complete the widget [12] system. These components are statically linked to the kernel. After linking, it is difficult to modify the system [17]. Conversely, Contiki provides a dynamic structure that allows programs and drivers to be replaced at run time without having to relink. To provide TinyOS with run-time reprogramming capabilities, Levis and Culler developed a virtual machine--mate[17 for TinyOS devices]. This virtual machine is designed for typical sensor network applications. Similarly, the Magneos operating system [7] uses a Java virtual machine to distribute the application to the sensor network. The benefit of using virtual machines instead of local machine code is that the virtual machine code can be written very small, reducing energy consumption when transferring code into the network. However, the disadvantage is that it increases the energy consumption of the explanatory code, because for long-running programs, the energy savings during the transmission of the binary code will be consumed when the code is executed. The Contiki program uses native code and can therefore be applied to various types of programs, including low-level device drivers that do not lose execution efficiency.
SENSORWARE[8] provides an abstract scripting language for programmable sensors, but their target platform is not a resource-constrained platform like ours. Similarly, the EMSTAR[3] environment is designed to be used in less resource constrained systems. Reijers and langendoen[21] use a patch language to change the binary image of a running system, which is valid in a network where all nodes run the same binary code, but becomes particularly complex once a little bit of different programs or versions of the program are different.
The Mantio operating system [3] uses traditional, preemptive multithreaded model operations. By downloading the program to the EEPROM and then from the EEPROM to the Flash ROM, the mantio supports both the re-programming of the complete operating system and the re-burning of some of the storage space. Because of the multithreading theory, each Mantis program must allocate stack space from the system heap, and the lock mechanism must be used to implement shared variable mutex. Conversely, Contiki has avoided multi-stack allocation and locking mechanisms by using event-based, non-preemption schedulers in turn. Preemptive multithreading is provided as a library and is linked to the program when needed.
Contiki is similar to fibers[4 in a preemptive multi-threading. The lightweight fibers has Welsh and mainland[23] implementations. The remainder of the lightweight fibers is different, Contiki does not limit the maximum number of current threads--2. Also, unlike fibers, threads in Contiki support preemption.
Similar to exokernel[11] and nemesis[16], Contiki minimizes the amount of abstraction to keep the kernel size minimized. Abstraction is implemented in the form of a library and is almost useful for full access to the underlying hardware. Exokernel Pursuit of performance, Nemesis pursuit of service quality, Contiki the pursuit of reducing size, maintain flexibility. Unlike Exokernel, Contiki does not support the protection mechanism because Contiki hardware does not support memory protection at design time.
3. System Overview A running Contiki system consists of a kernel, a library, a program loader, and a series of processes. A process can be an application or a service that provides functionality for multiple processes. All processes, including applications and services, can be dynamically loaded at run time. interprocess communication is always done through the kernel, but the kernel does not provide the message abstraction layer, and lets the device driver, the application directly communicates with the hardware.
A process has an event handler function (hander) or an optional polling handler (poll hander function) definition. The state of the process is saved in the private memory of the process, and there is only one pointer to that state in the kernel. In the ESB platform [5], the process state consists of 23 bytes. All processes share the same address space instead of running in different protection domains. Inter-process communication through the Postman event (posting events).
Figure 1. Partition--Kernel, loadable program
The Contiki system is divided into two parts: the core and the loaded program in Figure 1. Partitions are specified at compile time and are specific in the Contiki deployment. Typically, the core consists of a Contiki kernel, a program loader, a common part of the runtime, a supported library, and a communication stack used in device drivers to communicate with hardware. The core is compiled into a single binary image file and is prioritized for deployment to the device. After deployment, the core is not modified even if the program loader is used to overwrite the core or to patch the core.
The program is loaded into the system via the program loader. The program loader obtains program secondary files by using a communication stack or by using additional storage devices such as EEPROM directly. Typically, it is stored in the EEPROM before the program is burned to write memory, and then the system is loaded.
4. Kernel architecture The Contiki kernel consists of a lightweight scheduler. The scheduler Dispatches events to run the process and periodically invokes the process's polling processor. All programs are dispatched via a kernel-low-cylinder event or through a polling mechanism. Once the kernel is dispatched, the time processing area will not be preempted, so the time processor must run to the end. However, as you will see in the 8th chapter, the time processor must use an internal mechanism to implement preemption.
The kernel supports two types of events: asynchronous and synchronization time. An asynchronous event is a form of deferred processing invocation: An asynchronous event is a queue in the kernel that is dispatched to the target process after a certain period of time. Synchronous events are similar to asynchronous events, but are dispatched immediately to the target process that needs to be dispatched. When the target process finishes processing the event, the result is returned to the postman process. This is similar to the gate abstraction in the spring operating system and can be seen as a program call between processes.
In addition to events, the kernel provides a polling mechanism. Polling can be seen as a high-priority event dispatched in an asynchronous event. Polling for a process is typically used for hardware-related operations, such as checking the status of a car's hardware device. When a poll is dispatched, all processes that implement the polling processor will be dispatched according to their priority.
The Contiki kernel provides a unique shared stack for all process executions. Because the stack is inverted (rewound) When the event handler is called, the use of asynchronous events reduces the stack space.
4.1 Level Two scheduling all event schedules in Contiki are completed at one level, so events cannot preempt other event executions. Events can only be preempted by interrupts. Normally, interrupt events are implemented by hardware interrupts, but may also be implemented by the underlying real-time performer (an underlying real-time executive). The Linux kernel has used later techniques to provide real-time assurance.
In order to support a fundamental real-time execution, Contiki never shuts down interrupts. For this reason, Contiki does not allow interrupt processor dispatch events, as that can result in a race condition in the event handler. Instead, the kernel provides a polling token to request a polling event. This tag provides a way for the interrupt processor to request immediate polling.
4.2 The Loadable program can implement the loadable properties of the program through the run-time relocation feature, as well as the relocation information included in the binary format. When the loader loads the program into the system, it allocates as much memory as possible, based on information provided by level two. If the memory allocation fails, the program load is terminated.
After the program is loaded into memory, the loader invokes the program's initialization function. The initialization function of a program may start or replace one or more processes.
4.3 Power saving mode
In a sensor network, it is always desirable to turn off the power of the node when the network is inactive in order to reduce the energy consumption. The power protection mechanism depends on both the application [18] and the network protocol [20]. The Contiki kernel contains non-explicit power-saving abstractions, but it needs to be specified to implement this mechanism. To help the application decide when to power off the system, the time scheduler exposes the size of the time queue. When no events are scheduled, the processor can be shut down based on this information. The external event is handled by the polling processor when the processor response interrupt is awakened.
5. Service
Figure 2: Procedure for applying a function to invoke a service
In Contiki, a service is a process that provides specific functionality to other processes and can be seen as a form of shared libraries. Services can be dynamically replaced at run time, and therefore must also be dynamically linked. Typical services include communication protocol stacks, sensor device drivers, and high-level features such as sensor data processing algorithms.
The service layer is tightly close to the kernel and is responsible for managing services. Specifically, the service layer is responsible for tracking the services that are running and provides a way to locate the services that are installed. A service is identified by a text string and is used to describe the service. The service layer uses a common string matching method to query the services that are already installed.
A service consists of a service interface and the process that implements the interface. A service interface consists of a version number and a function table. A function table consists of a function pointer that points to the function interface.
The application communicates with the service through the root library. Genku is linked to the application and then uses the service layer to find the process that the service corresponds to. Once a service is located, the root caches the process ID of the service process for all future service requests.
The program invokes the service through the service interface root. In the process of invoking a service, the program does not have to know that the interface he is invoking is a special interface for the service. When the service is first called, the service interface root looks for the service at the service layer. If the specified service exists, the lookup returns a pointer to the service interface, and the version number in the service interface is checked against the version number in the root. In addition to the version number, a pointer to the service function is included in the service interface. If the version number in the service root matches the version number in the service interface successfully, the service interface root invokes the requested function.
5.1 Service Replacement
As with all processes, services can be dynamically loaded and replaced in a running Contiki system. Because the process ID of the service process is used to identify the process, preserving its process ID is critical if the service process is replaced. For this reason, the kernel provides a special mechanism for replacing processes and preserving process IDs.
When a service is replaced, the kernel mails a special event to the service process. As a response to the event, the service must remove itself from the system.
Many services have a state inside that is used to pass to a new process. The kernel provides a way to pass a pointer to a new service process where a new service process can produce a status descriptor that describes the state of the process, based on the incoming state. The memory that holds the state must be allocated from the shared source because the process memory is redistributed when the old process is removed.
The service's status descriptor contains the version number of the service, so the kernel does not attempt to load the same service with an incompatible version number.
6. Library
The Contiki kernel provides only the most basic CPU reuse and event handling features, and the rest of the system is implemented in the form of a system library and is optionally linked to the program. There are three ways to link a program to a library. The first, a library that is part of the core, is statically linked to the program. The second, a library that is part of a loadable program, is statically linked to the program. Third, the program can invoke the service to implement a particular library. A library that exists as a service that can be dynamically replaced at run time.
Typically, runtime libraries, such as libraries that are often used, are best placed in the Contiki core. Rarely used, or application-related libraries, more suitable for linking to loadable programs. Libraries that are part of the core are always present in the system and therefore do not have to be included in the Loadable library.
For example, suppose the program uses the function memcpy () to copy the memory, using Atoi () to convert the string to an integer. The function memcpy () is a frequently used C library function, and atoi () is not used so much. Therefore, in this particular case, memcpy () will be included in the system core, and Atoi () will not be included. When the program is linked to binary, the static address of the function memcpy () will be linked to the core again. However, the part of the target code that implements Auoi () in the C library must be included in the binary of the program.
7. Communication support
Figure 3: Communication stack
Communication is a fundamental concept in a sensor network. In Contiki, communication is implemented as a service in order to make run-time substitution possible. Multiple communication stacks are loaded simultaneously. Experimental studies have found that this can be used to evaluate and compare different communication protocols. Also, as shown in 3, a communication stack may be divided into different services, which is where the runtime replaces some of the communication stacks.
The Communication Service uses the service mechanism to invoke other services and uses synchronization events to communicate with the application. Since the synchronization event handler is required to run to the end once it has been run, this makes it possible to use a buffer for the desired communication processing. The device driver reads the received packet into the communication buffer and then calls the upper layer of the communication Service. The communication stack is responsible for processing the header and mailing a synchronization event to the application informing the package that it has been received. The application responds to the contents of the package, optionally maintaining a response in buffer, and finally returns control to the communication stack. The communication stack is pre-prepared to be sent to the outside of the new header, and then the control is given to the device driver, thus completing a packet transfer.
8. Can preemptive multi-threading
In Contiki, preemptive multithreading is implemented as a library on top of the event-based kernel. Libraries are linked to an application in an optional form, where the application explicitly indicates that a multithreaded model operation is required before the library is linked to the application. Libraries are divided into two categories: the platform-independent part-used to interact with the event kernel, and the platform-related parts-to implement the switching and preemption mechanism of the stack. Typically, preemption is implemented by a timer interrupt, keeping the processor's register in the stack, and then switching back to the kernel stack. In practice, when porting platform-related partial libraries, you only need to rewrite very little code. For example, for the MSP430 platform, only 25 lines of C code are used.
Unlike the regular Contiki process, each thread requires a separate stack. The necessary stack management functions are provided in the library. Each thread executes on its own stack before it is explicitly rolled out or preempted.
Figure 4: API for multi-line libraries
Figure 4 shows the APIs in a multithreaded library. It consists of six functions (Mt_yield (), Mt_post (), mt_wait (), Mt_exit (), Mt_start () and Mt_exec ()). The Mt_exec () function is called by the event handler to perform the actual thread dispatch.
9. Discussion
We have implemented many sensor network applications with the Contiki operating system, such as multi-hop routing, motion Detection.
9.1 Aerial programming (over-the-air programming)
We have implemented a simple aerial programming protocol. The protocol uses point-to-point communication to transmit a single binary file to the selected hub. The binary file is stored in the EEPROM and is broadcast to the neighbor node when the complete program is received by this node. If a packet loss occurs, a low level signal can be signaled by a neighbor node and then repaired by a hub node. We intend to implement better protocols in the future, such as the trickle algorithm.
We did an experiment to dynamically distribute 40 nodes to the alarm system. We use the aerial reprogramming method and the manual wired reprogramming method. Initially, the program loading mechanism was not perfect, and it was not possible to use the program to load in our experiment. Our target program is approximately 6KB, plus the Contiki core and C libraries, and the complete system image is close to 30KB. Using manual wired reprogramming, programming for a separate sensor node took more than 30 seconds. With a total of 40 checkpoints, it takes at least 30 minutes to program the entire network. Conversely, by means of the aerial reprogramming method, only 2 minutes were used, which reduced an order of magnitude.
9.2 Code Size
Table 1. Compiled code size (bytes)
For an operating system developed for a restricted device, the size of the code and the utilization of RAM must be small enough to leave enough space for the application running on top of the system. Table 1 shows the code size and RAM utilization for Contiki on two architectures: TI MSP430 and Atmel AVR. The figures in the table translate core components and application cases-the size of the sensor data Replication service. This data replication service consists of two parts: the service interface root and the service itself implementation. Currently, the program loader is only implemented on the MSP430 platform.
Contiki code size is larger than tinyos, smaller than the mantis system. Because of the different services provided, Contiki's event kernel is much more natural than tinyos. The TinyOS event kernel only provides a FIFO event queue scheduler, while the Contiki kernel supports both FIFO events and priority rotation processors. Also, for tinyos such systems, the flexibility of Contiki requires more runtime code.
The requirements for RAM depend on the maximum number of processes configured by the system (p), the maximum size of the asynchronous event queue (e), and the thread stack size (s) in multithreaded operations.
9.3 Preemptive Type
Figure 5: There is a small increment in response time during a preemptive calculation
The purpose of preemption is to make long-running operations more meaningful and responsive to incoming events, such as sensor input or incoming communication packets. Figure 5 depicts how a preemptive thread that takes 8 seconds to complete can respond to incoming traffic packets when Contiki is running. The curve is tested by 200 round-trip ping packets (40 direct per package). The process of pinging the package ends approximately from the 5th second to the 13th second. During this time, round-trip times have increased slightly but still respond to ping packets.
Our test method is to send the package to the ESB node running Contiki every 200ms, from the 1.4GHz pc through the 57600kb/s speed. Packets are passed through a serial line instead of wirelessly, to avoid radio effects such as bit dislocation or Mac collisions.
9.4 Portability
We have ported Contiki to many architectures, including Ti MSP430 and Atmel AVR. Others have kept the system up to Hitachi SH3 and Zilog Z80. The porting process includes write-startup code, device-driven, schema-related program loaders, and stack switch codes in multi-threaded libraries. There is no need to make any changes to the kernel and service tiers.
Because the kernel and the service layer do not require any changes, the first I/O driver finishes writing the actual port test. Port porting for the Atem AVR was done by ourselves, including a valid device driver, which took only 2 hours. Port porting for Zilog Z80 was completed by a third party and only took one day.
10. Summary
We have described the Contiki operating system designed for memory-constrained systems. To reduce the size of the system, Contiki is based on the event-driven kernel. Because it is difficult for long-running programs to use state machine programming in event-driven systems. Contiki provides a preemptive multi-threaded application library that runs on top of the event-driven kernel, which is optionally linked to the application, i.e., when the application explicitly describes the need for a multi-threading model.
A running Contiki is divided into two parts: the core and the Loadable program. The core consists of the kernel, some class basic services, the Language runtime section, and the supported libraries. The loader can be loaded and unloaded independently at run time. Shared functionality is implemented as a shared library. Services can be updated or replaced independently, and system flexibility is added.
We can see that, while keeping the basic system lightweight and compact, you have the flexibility to load, unload programs and services on resource-constrained systems. Although our kernel is event-driven, it also provides preemptive multithreaded support for applications.
Due to the dynamic characteristics of Contiki, it can be used for multi-hardware, multi-application and even multi-user of sensor networks. We will continue our work in support of security mechanisms.
contiki--Lightweight, flexible operating system for micro-sensor networks