The Long Jump
A good friend of mind, Tom, was an accomplished sky diver in his Air Force days. He often tells of how many times he'd walked on a plane before he ever walked out of one. That is, his first time up in a plane he jumped out of it! I'm more of the school that if the plane isn't in trouble, I'm going to stay inside, but to each their own, I suppose.
Like most assembly language programmers, I don't fear the GOTO or jump. But most high-level language people avoid it like the plague. It all started in 1968 with Edsger Dijkstra's letter to the Communications of the ACM, titled "Go To Statement Considered Harmful". Now, almost 40 years later, I meet C programmers all the time who don't even realize C contains a goto
keyword!
I'm not seriously suggesting that goto
is useful that often. Even though there are a few cases where it does make sense (as noted in this discussion), most of us just conform rather than have to explain our reasoning. Of course, there are always those that are rebellious and add goto
to Java. You could even argue that goto
just went underground in the form of exceptions, switch statements…but I hate to get involved with theology.
The reason I've been thinking about goto
is that I decided to see just how simple of an "operating system" I could create for small computers (things like a Microchip PIC or Atmel AVR). I know there are plenty of choices out there already. But I wanted to see just how far I could strip things, plus Dr. Dobb's has a long history of "Roll your Own…" articles and I was in the mood. It turns out being able to create a form of goto
is crucial to just about every multitasking system.
I wanted something simple and portable, so I naturally thought of C and a cooperative multitasking system. In a cooperative system, each task runs until it agrees to give up the CPU. This has advantages (simplicity, strict control of concurrency, and timing) and some disadvantages (an errant task can simply refuse to relinquish the CPU). Early versions of Windows operated on this principle, although modern versions use the more common preemptive multitasking where a task is forcibly stopped after a certain amount of time.
In the back of my mind, I knew I'd seen several schemes for building cooperative multitasking using setjmp/longjmp
. If there are programmers that don't know about the goto
statement, there are even more than missed out on setjmp/longjmp
. These are functions in the standard C library that let you "bookmark" a spot in your code and then jump back to that bookmark later. Unlike a regular goto
, you can jump back from anywhere. Consider this example:
#include <stdio.h> #include <setjmp.h> jmp_buf go; void helper(void) { printf("two, "); // instead of a return we will jump back to main // using the buffer set up there longjmp(go,1); } int main(int argc, char *argv[]) { printf("One, "); // prepare for a future long jump // return of 0 means we just // set up the buffer if (!setjmp(go)) { helper(); // not reached unless helper returns printf("I got the flu!\n"); return 1; } // the long jmp will wind up here printf("buckle my shoe.\n"); return 0; }
This is somewhat contrived, but it does show how the pair of functions works. The program's main
calls setjmp
with a jmp_buf
argument. This populates the buffer (the "bookmark") and returns a zero.
The code then proceeds to call helper
. Inside helper
, a longjmp
executes using the bookmark and a return value (presumably not zero; one in this case). That causes execution to resume at the bookmark. The string "I got the flu!"
never executes (nor does the return of 1). Instead, the program acts as if setjmp
returned a 1 (the argument to longjmp
) and execution continues.