In this thesis I focus on three topics pertaining to programming memory- constrained networked embedded systems: the use of the TCP/IP protocol suite for memory-constrained embedded systems; a novel programming abstraction that I have namedprotothreads, which is intended to simplify event-driven
1.4 Research Issues 7
programming of memory-constrained systems; and dynamic loading of native code modules in my Contiki operating system for memory-constrained system. A general theme throughout this research is the use of standard or general- purpose mechanisms. In academic research we are not restricted to standards. Rather, we can freely choose to investigate our own protocols, programming languages, file formats, and mechanisms. This is partly due to that we often work in areas in which no standards have been created. However, even in areas where standards exist or are emerging we often develop and use our own protocols, programming languages, file formats, and mechanisms. Because of this we cannot be sure why we choose our own solutions over the standard solutions. Do we go our own way because we want to? Or are we compelled to do it because of the overheads of the standard solutions?
Part of the research in this thesis is about answering the question of how far we can push general-purpose or standard mechanisms before we need to invent our own mechanisms. Or, conversely, how well does general-purpose and standard mechanisms work for memory-constrained systems?
1.4.1
TCP/IP for Memory-Constrained Systems
All systems connected to the global Internet, wireless networks such as WLAN and GPRS, and many local area networks communicate using the standard TCP/IP protocol suite. Due to the prevalence of TCP/IP networks many net- worked embedded systems are connected to such networks and therefore must be able to communicate using the TCP/IP protocols. However, the TCP/IP pro- tocol suite is often perceived to be “heavy-weight” in that an implementation of the protocols requires large amounts of resources in terms of memory and pro- cessing power. This perception can be corroborated by measuring the memory requirements of popular TCP/IP implementations, such as the one in the Linux kernel [28] or in the BSD operating system [52]. The TCP/IP implementations in these systems require many hundreds of kilobytes of RAM and have a code footprint of approximately hundred kilobytes.
The perception that the TCP/IP protocols would require large amounts of memory leads to system designers equipping their embedded systems with large microprocessors. If it was possible to implement the TCP/IP protocol suite in radically less memory, system designers could choose smaller micro- processors for their embedded systems. This would not only make the resulting systems less costly to produce, but would also enable an entire class of smaller embedded systems to communicate using the TCP/IP protocol suite. This is the focus of Paper A.
8 Chapter 1. Introduction
1.4.2
Protothreads and Event-Driven Programming
Networked embedded systems must handle multiple events that occur concur- rently; they must handle both interactions with the physical world and interac- tions with other systems that communication over the network. To handle con- currency in a small amount of memory, many memory-constrained networked embedded systems are built on an event-driven programming model rather than a multithreaded model [29, 53].
In the multithreaded model concurrency is implemented by designing the system as a set of threads. Each thread is a program that runs concurrently with the other threads in the system. Threads can wait for events to occur. The thread then blocks its execution until it is woken up by the operating system. Each thread requires its own processor stack. In a memory-constrained system, multiple stacks may require a large part of the total memory.
In the event-driven model, the system is not made up of threads but of event handlers that all run on the same stack. Since only one stack is used, the memory requirements are reduced. In the event-driven model all program execution is triggered by internal or external events. When an event occurs, an event handler is invoked by the event dispatcher. Event handlers cannot wait for events to occur but must explicitly return control to the event dispatcher. The fact that event handlers cannot do a blocked wait complicates implementation of high-level logic that cannot be expressed as a single event handler. Such logic must be divided into multiple event handlers where the flow control of the logic is implemented as explicit state machines. Such state machines typically are difficult to write, read, and debug [6, 23, 42, 44, 67].
If it was possible to somehow combine the multithreaded and the event- driven model, perhaps programs could be written in a sequential style without explicit state machines and still have a low memory overhead. Furthermore, it would be advantageous if it was possible to do this in a standard, general- purpose programming language. The study of this problem is initiated in Paper B and continued in Papers C and D.
1.4.3
Dynamic Module Loading
Most operating systems for memory-constrained embedded systems are de- signed in a monolithic fashion where the operating system, hardware device drivers, and all application programs are compiled into a single monolithic bi- nary that is installed in the read-only memory of the microprocessor in the embedded system. This monolithic approach has its benefits, such as memory