To Be Continued: Local Continuations with the Protothreads Library
Last time I talked about using threads on the Arduino via the protothreads library. I mentioned that protothreads uses a "local continuation" scheme to jump from thread to thread.
If you look at the protothread implementation, there are actually three ways it can do local continuations:
- Machine-specific code written in assembler
- Standard C constructs (specifically, a subverting of the C switch statement)
- Compiler-specific extensions
The first method is great, but (unsurprisingly) non-portable. It also consumes more memory than the other techniques. The author quotes 16 to 32 bytes of overhead per thread, but it stands to reason that this would depend completely on the CPU involved so, in theory, it could be even worse.
The standard C implementation only requires two bytes per thread. It borrows from the Tatham's coroutines in C implementation. Tatham takes advantage of the fact that a case label is legal in any subblock of switch statement.
The ugly downside, however, is that your threads then can't use switch statements (because the critical case labels will then belong to your switch instead of the protothread switch).
The example I used last time selected the third method by virtue of the following two lines:
#define LC_INCLUDE <lc-addrlabels.h> // use gcc LC #include <pt.h>
The lc-addrlabels.h file is part of protothreads and uses a gcc extension that allows you to take the address of a label. The GNU C compiler defines the && operator that allows you to get the address of a label as a constant void pointer. The label has to be in the current function scope or an enclosing scope.
Armed with a void pointer to an address (say,
addr) you can jump to it:
void *addr=&&somewhere; goto *addr; . . . somewhere: do_something();
There are quite a few restrictions on using labels this way, and it is probably best considered a "hack" in most cases. However, using protothreads, you don't need to see the ugly details.
You might wonder why I have been thinking about operating systems on Arduino lately. Part of it is because I recently acquired what can only be described as a "huge" Arduino board: the Intel Galileo. This behemoth is really an embedded Linux board. It has an x86 processor, Ethernet, a flash memory slot, and USB. It even has a mini PCIe slot! However, it also has the pin out of a standard Arduino and enough smarts to work like an Arduino (mostly; it can actually execute Arduino and Linux programs at the same time).
Now that's an operating system for Arduino. As you might expect, though, there are some positives and negatives to such an approach. I'll have more to say about my experiences with the Galileo in upcoming blogs.