Setjmp.h
- 12 min read
- 4 chapters
Related on Lably
Through Control flow, Function (computer programming) and Exception handling
A typical use of setjmp/longjmp is implementation of an exception mechanism that exploits the ability of longjmp to reestablish program or thread state, even across multiple levels of function calls. A less common use of setjmp is to create syntax similar to coroutines.
Member functions
setjmp saves the current environment (the program state), at some point of program execution, into a platform-specific data structure (jmp_buf) that can be used at some later point of program execution by longjmp to restore the program state to that saved by setjmp into jmp_buf. This process can be imagined to be a "jump" back to the point of program execution where setjmp saved the environment. The (apparent) return value from setjmp indicates whether control reached that point normally (zero) or from a call to longjmp (nonzero). This leads to a common idiom: if( setjmp(x) ){/* handle longjmp(x) */}.
POSIX.1 does not specify whether setjmp and longjmp save and restore the current set of blocked signals; if a program employs signal handling it should use POSIX's sigsetjmp/siglongjmp.
Sign in to keep reading
3 more chapters are free with a Lably account.
Member types
The C99 Rationale describes jmp_buf as being an array type for backward compatibility; existing code refers to jmp_buf storage locations by name (without the & address-of operator), which is only possible for array types. It notes that it can simply be a one-member-long array with its single member being the actual data; indeed, this is the approach employed by the GNU C library, which defines the type as struct __jmp_buf_tag[1].
Caveats and limitations
When a "non-local goto" is executed via setjmp/longjmp in C++, normal "stack unwinding" does not occur. Therefore, any required cleanup actions will not occur either. This could include closing file descriptors, flushing buffers, or freeing heap-allocated memory.
If the function in which setjmp was called returns, it is no longer possible to safely use longjmp with the corresponding jmp_buf object. This is because the stack frame is invalidated when the function returns. Calling longjmp restores the stack pointer, which—because the function returned—would point to a non-existent and potentially overwritten or corrupted stack frame.
Similarly, C99 does not require that longjmp preserve the current stack frame. This means that jumping into a function which was exited via a call to longjmp is undefined.
Example usage
Simple example
The example below shows the basic idea of setjmp. There, main() calls first(), which in turn calls second(). Then, second() jumps back into main(), skipping first()'s call of printf().
<span id="mwqA"></span><span class="cp" id="mwqQ">#include</span><span class="w" id="mwqg"> </span><span class="cpf" id="mwqw"><stdio.h></span> <span class="cp" id="mwrA">#include</span><span class="w" id="mwrQ"> </span><span class="cpf" id="mwrg"><setjmp.h></span> <span class="k" id="mwrw">static</span><span class="w" id="mwsA"> </span><span class="kt" id="mwsQ">jmp_buf</span><span class="w" id="mwsg"> </span><span class="n" id="mwsw">buf</span><span class="p" id="mwtA">;</span> <span class="kt" id="mwtQ">void</span><span class="w" id="mwtg"> </span><span class="nf" id="mwtw">second</span><span class="p" id="mwuA">()</span><span class="w" id="mwuQ"> </span><span class="p" id="mwug">{</span> <span class="w" id="mwuw"> </span><span class="n" id="mwvA">printf</span><span class="p" id="mwvQ">(</span><span class="s" id="mwvg">"second</span><span class="se" id="mwvw">\n</span><span class="s" id="mwwA">"</span><span class="p" id="mwwQ">);</span><span class="w" id="mwwg"> </span><span class="c1" id="mwww">// prints</span> <span class="w" id="mwxA"> </span><span class="n" id="mwxQ">longjmp</span><span class="p" id="mwxg">(</span><span class="n" id="mwxw">buf</span><span class="p" id="mwyA">,</span><span class="w" id="mwyQ"> </span><span class="mi" id="mwyg">1</span><span class="p" id="mwyw">);</span><span class="w" id="mwzA"> </span><span class="c1" id="mwzQ">// jumps back to where setjmp was called - making setjmp now return 1</span> <span class="p" id="mwzg">}</span> <span class="kt" id="mwzw">void</span><span class="w" id="mw0A"> </span><span class="nf" id="mw0Q">first</span><span class="p" id="mw0g">()</span><span class="w" id="mw0w"> </span><span class="p" id="mw1A">{</span> <span class="w" id="mw1Q"> </span><span class="n" id="mw1g">second</span><span class="p" id="mw1w">();</span> <span class="w" id="mw2A"> </span><span class="n" id="mw2Q">printf</span><span class="p" id="mw2g">(</span><span class="s" id="mw2w">"first</span><span class="se" id="mw3A">\n</span><span class="s" id="mw3Q">"</span><span class="p" id="mw3g">);</span><span class="w" id="mw3w"> </span><span class="c1" id="mw4A">// does not print</span> <span class="p" id="mw4Q">}</span> <span class="kt" id="mw4g">int</span><span class="w" id="mw4w"> </span><span class="nf" id="mw5A">main</span><span class="p" id="mw5Q">()</span><span class="w" id="mw5g"> </span><span class="p" id="mw5w">{</span> <span class="w" id="mw6A"> </span><span class="k" id="mw6Q">if</span><span class="w" id="mw6g"> </span><span class="p" id="mw6w">(</span><span class="o" id="mw7A">!</span><span class="n" id="mw7Q">setjmp</span><span class="p" id="mw7g">(</span><span class="n" id="mw7w">buf</span><span class="p" id="mw8A">))</span> <span class="w" id="mw8Q"> </span><span class="n" id="mw8g">first</span><span class="p" id="mw8w">();</span><span class="w" id="mw9A"> </span><span class="c1" id="mw9Q">// when executed, setjmp returned 0</span> <span class="w" id="mw9g"> </span><span class="k" id="mw9w">else</span><span class="w" id="mw-A"> </span><span class="c1" id="mw-Q">// when longjmp jumps back, setjmp returns 1</span> <span class="w" id="mw-g"> </span><span class="n" id="mw-w">printf</span><span class="p" id="mw_A">(</span><span class="s" id="mw_Q">"main</span><span class="se" id="mw_g">\n</span><span class="s" id="mw_w">"</span><span class="p" id="mwAQA">);</span><span class="w" id="mwAQE"> </span><span class="c1" id="mwAQI">// prints</span> <span class="w" id="mwAQM"> </span><span class="k" id="mwAQQ">return</span><span class="w" id="mwAQU"> </span><span class="mi" id="mwAQY">0</span><span class="p" id="mwAQc">;</span> <span class="p" id="mwAQg">}</span>When executed, the above program will output:
second main
Notice that although the first() subroutine gets called, "first" is never printed, as second() never returns control to first(). Instead, "main" is printed when the conditional statement if (!setjmp(buf)) is checked a second time.
Exception handling
In this example, setjmp is used to bracket exception handling, like try in some other languages. The call to longjmp is analogous to a throw statement, allowing an exception to return an error status directly to the setjmp. The following code adheres to the 1999 ISO C standard and Single UNIX Specification by invoking setjmp in a limited range of contexts:
- As the condition to an
if,switchor iteration statement - As above in conjunction with a single
!or comparison with an integer constant - As a statement (with the return value unused)
Following these rules can make it easier for the implementation to create the environment buffer, which can be a sensitive operation. More general use of setjmp can cause undefined behaviour, such as corruption of local variables; conforming compilers and environments are not required to protect or even warn against such usage. However, slightly more sophisticated idioms such as switch ((exception_type = setjmp(env))) { } are common in literature and practice, and remain relatively portable. A simple conforming methodology is presented below, where an additional variable is maintained along with the state buffer. This variable could be elaborated into a structure incorporating the buffer itself.
In a more modern-looking example, the usual "try" block would be implemented as a setjmp (with some preparation code for multilevel jumps, as seen in first), the "throw" as longjmp with the optional parameter as the exception, and the "catch" as the "else" block under "try".
<span id="mwAS8"></span><span class="cp" id="mwATA">#include</span><span class="w" id="mwATE"> </span><span class="cpf" id="mwATI"><setjmp.h></span> <span class="cp" id="mwATM">#include</span><span class="w" id="mwATQ"> </span><span class="cpf" id="mwATU"><stdio.h></span> <span class="cp" id="mwATY">#include</span><span class="w" id="mwATc"> </span><span class="cpf" id="mwATg"><stdlib.h></span> <span class="cp" id="mwATk">#include</span><span class="w" id="mwATo"> </span><span class="cpf" id="mwATs"><string.h></span> <span class="k" id="mwATw">static</span><span class="w" id="mwAT0"> </span><span class="kt" id="mwAT4">void</span><span class="w" id="mwAT8"> </span><span class="nf" id="mwAUA">first</span><span class="p" id="mwAUE">();</span> <span class="k" id="mwAUI">static</span><span class="w" id="mwAUM"> </span><span class="kt" id="mwAUQ">void</span><span class="w" id="mwAUU"> </span><span class="nf" id="mwAUY">second</span><span class="p" id="mwAUc">();</span> <span class="cm" id="mwAUg">/* Use a file scoped static variable for the exception stack so we can access</span> <span class="cm" id="mwAUk"> * it anywhere within this translation unit. */</span> <span class="k" id="mwAUo">static</span><span class="w" id="mwAUs"> </span><span class="kt" id="mwAUw">jmp_buf</span><span class="w" id="mwAU0"> </span><span class="n" id="mwAU4">exception_env</span><span class="p" id="mwAU8">;</span> <span class="k" id="mwAVA">static</span><span class="w" id="mwAVE"> </span><span class="kt" id="mwAVI">int</span><span class="w" id="mwAVM"> </span><span class="n" id="mwAVQ">exception_type</span><span class="p" id="mwAVU">;</span> <span class="kt" id="mwAVY">int</span><span class="w" id="mwAVc"> </span><span class="nf" id="mwAVg">main</span><span class="p" id="mwAVk">(</span><span class="kt" id="mwAVo">void</span><span class="p" id="mwAVs">)</span><span class="w" id="mwAVw"> </span><span class="p" id="mwAV0">{</span> <span class="w" id="mwAV4"> </span><span class="kt" id="mwAV8">char</span><span class="o" id="mwAWA">*</span><span class="w" id="mwAWE"> </span><span class="k" id="mwAWI">volatile</span><span class="w" id="mwAWM"> </span><span class="n" id="mwAWQ">mem_buffer</span><span class="w" id="mwAWU"> </span><span class="o" id="mwAWY">=</span><span class="w" id="mwAWc"> </span><span class="nb" id="mwAWg">NULL</span><span class="p" id="mwAWk">;</span> <span class="w" id="mwAWo"> </span><span class="k" id="mwAWs">if</span><span class="w" id="mwAWw"> </span><span class="p" id="mwAW0">(</span><span class="n" id="mwAW4">setjmp</span><span class="p" id="mwAW8">(</span><span class="n" id="mwAXA">exception_env</span><span class="p" id="mwAXE">))</span><span class="w" id="mwAXI"> </span><span class="p" id="mwAXM">{</span> <span class="w" id="mwAXQ"> </span><span class="c1" id="mwAXU">// if we get here there was an exception</span> <span class="w" id="mwAXY"> </span><span class="n" id="mwAXc">printf</span><span class="p" id="mwAXg">(</span><span class="s" id="mwAXk">"first failed, exception type: %d</span><span class="se" id="mwAXo">\n</span><span class="s" id="mwAXs">"</span><span class="p" id="mwAXw">,</span><span class="w" id="mwAX0"> </span><span class="n" id="mwAX4">exception_type</span><span class="p" id="mwAX8">);</span> <span class="w" id="mwAYA"> </span><span class="p" id="mwAYE">}</span><span class="w" id="mwAYI"> </span><span class="k" id="mwAYM">else</span><span class="w" id="mwAYQ"> </span><span class="p" id="mwAYU">{</span> <span class="w" id="mwAYY"> </span><span class="c1" id="mwAYc">// Run code that may signal failure via longjmp.</span> <span class="w" id="mwAYg"> </span><span class="n" id="mwAYk">puts</span><span class="p" id="mwAYo">(</span><span class="s" id="mwAYs">"calling first"</span><span class="p" id="mwAYw">);</span> <span class="w" id="mwAY0"> </span><span class="n" id="mwAY4">first</span><span class="p" id="mwAY8">();</span> <span class="w" id="mwAZA"> </span><span class="n" id="mwAZE">mem_buffer</span><span class="w" id="mwAZI"> </span><span class="o" id="mwAZM">=</span><span class="w" id="mwAZQ"> </span><span class="n" id="mwAZU">malloc</span><span class="p" id="mwAZY">(</span><span class="mi" id="mwAZc">300</span><span class="p" id="mwAZg">);</span><span class="w" id="mwAZk"> </span><span class="c1" id="mwAZo">// allocate a resource</span> <span class="w" id="mwAZs"> </span><span class="n" id="mwAZw">printf</span><span class="p" id="mwAZ0">(</span><span class="s" id="mwAZ4">"%s</span><span class="se" id="mwAZ8">\n</span><span class="s" id="mwAaA">"</span><span class="p" id="mwAaE">,</span><span class="w" id="mwAaI"> </span><span class="n" id="mwAaM">strcpy</span><span class="p" id="mwAaQ">(</span><span class="n" id="mwAaU">mem_buffer</span><span class="p" id="mwAaY">,</span><span class="w" id="mwAac"> </span><span class="s" id="mwAag">"first succeeded"</span><span class="p" id="mwAak">));</span><span class="w" id="mwAao"> </span><span class="c1" id="mwAas">// not reached</span> <span class="w" id="mwAaw"> </span><span class="p" id="mwAa0">}</span> <span class="w" id="mwAa4"> </span><span class="n" id="mwAa8">free</span><span class="p" id="mwAbA">(</span><span class="n" id="mwAbE">mem_buffer</span><span class="p" id="mwAbI">);</span><span class="w" id="mwAbM"> </span><span class="c1" id="mwAbQ">// NULL can be passed to free, no operation is performed</span> <span class="w" id="mwAbU"> </span><span class="k" id="mwAbY">return</span><span class="w" id="mwAbc"> </span><span class="mi" id="mwAbg">0</span><span class="p" id="mwAbk">;</span> <span class="p" id="mwAbo">}</span> <span class="k" id="mwAbs">static</span><span class="w" id="mwAbw"> </span><span class="kt" id="mwAb0">void</span><span class="w" id="mwAb4"> </span><span class="nf" id="mwAb8">first</span><span class="p" id="mwAcA">()</span><span class="w" id="mwAcE"> </span><span class="p" id="mwAcI">{</span> <span class="w" id="mwAcM"> </span><span class="kt" id="mwAcQ">jmp_buf</span><span class="w" id="mwAcU"> </span><span class="n" id="mwAcY">my_env</span><span class="p" id="mwAcc">;</span> <span class="w" id="mwAcg"> </span><span class="n" id="mwAck">puts</span><span class="p" id="mwAco">(</span><span class="s" id="mwAcs">"entering first"</span><span class="p" id="mwAcw">);</span><span class="w" id="mwAc0"> </span><span class="c1" id="mwAc4">// reached</span> <span class="w" id="mwAc8"> </span><span class="n" id="mwAdA">memcpy</span><span class="p" id="mwAdE">(</span><span class="n" id="mwAdI">my_env</span><span class="p" id="mwAdM">,</span><span class="w" id="mwAdQ"> </span><span class="n" id="mwAdU">exception_env</span><span class="p" id="mwAdY">,</span><span class="w" id="mwAdc"> </span><span class="k" id="mwAdg">sizeof</span><span class="w" id="mwAdk"> </span><span class="n" id="mwAdo">my_env</span><span class="p" id="mwAds">);</span><span class="w" id="mwAdw"> </span><span class="c1" id="mwAd0">// store value of exception_env in my_env since exception_env will be reused</span> <span class="w" id="mwAd4"> </span><span class="k" id="mwAd8">switch</span><span class="w" id="mwAeA"> </span><span class="p" id="mwAeE">(</span><span class="n" id="mwAeI">setjmp</span><span class="p" id="mwAeM">(</span><span class="n" id="mwAeQ">exception_env</span><span class="p" id="mwAeU">))</span><span class="w" id="mwAeY"> </span><span class="p" id="mwAec">{</span> <span class="w" id="mwAeg"> </span><span class="k" id="mwAek">case</span><span class="w" id="mwAeo"> </span><span class="mi" id="mwAes">3</span><span class="p" id="mwAew">:</span><span class="w" id="mwAe0"> </span><span class="c1" id="mwAe4">// if we get here there was an exception.</span> <span class="w" id="mwAe8"> </span><span class="n" id="mwAfA">puts</span><span class="p" id="mwAfE">(</span><span class="s" id="mwAfI">"second failed, exception type: 3; remapping to type 1"</span><span class="p" id="mwAfM">);</span> <span class="w" id="mwAfQ"> </span><span class="n" id="mwAfU">exception_type</span><span class="w" id="mwAfY"> </span><span class="o" id="mwAfc">=</span><span class="w" id="mwAfg"> </span><span class="mi" id="mwAfk">1</span><span class="p" id="mwAfo">;</span> <span class="w" id="mwAfs"> </span><span class="k" id="mwAfw">default</span><span class="o" id="mwAf0">:</span><span class="w" id="mwAf4"> </span><span class="c1" id="mwAf8">// fall through</span> <span class="w" id="mwAgA"> </span><span class="n" id="mwAgE">memcpy</span><span class="p" id="mwAgI">(</span><span class="n" id="mwAgM">exception_env</span><span class="p" id="mwAgQ">,</span><span class="w" id="mwAgU"> </span><span class="n" id="mwAgY">my_env</span><span class="p" id="mwAgc">,</span><span class="w" id="mwAgg"> </span><span class="k" id="mwAgk">sizeof</span><span class="w" id="mwAgo"> </span><span class="n" id="mwAgs">exception_env</span><span class="p" id="mwAgw">);</span><span class="w" id="mwAg0"> </span><span class="c1" id="mwAg4">// restore exception stack</span> <span class="w" id="mwAg8"> </span><span class="n" id="mwAhA">longjmp</span><span class="p" id="mwAhE">(</span><span class="n" id="mwAhI">exception_env</span><span class="p" id="mwAhM">,</span><span class="w" id="mwAhQ"> </span><span class="n" id="mwAhU">exception_type</span><span class="p" id="mwAhY">);</span><span class="w" id="mwAhc"> </span><span class="c1" id="mwAhg">// continue handling the exception</span> <span class="w" id="mwAhk"> </span><span class="k" id="mwAho">case</span><span class="w" id="mwAhs"> </span><span class="mi" id="mwAhw">0</span><span class="p" id="mwAh0">:</span><span class="w" id="mwAh4"> </span><span class="c1" id="mwAh8">// normal, desired operation</span> <span class="w" id="mwAiA"> </span><span class="n" id="mwAiE">puts</span><span class="p" id="mwAiI">(</span><span class="s" id="mwAiM">"calling second"</span><span class="p" id="mwAiQ">);</span><span class="w" id="mwAiU"> </span><span class="c1" id="mwAiY">// reached </span> <span class="w" id="mwAic"> </span><span class="n" id="mwAig">second</span><span class="p" id="mwAik">();</span> <span class="w" id="mwAio"> </span><span class="n" id="mwAis">puts</span><span class="p" id="mwAiw">(</span><span class="s" id="mwAi0">"second succeeded"</span><span class="p" id="mwAi4">);</span><span class="w" id="mwAi8"> </span><span class="c1" id="mwAjA">// not reached</span> <span class="w" id="mwAjE"> </span><span class="p" id="mwAjI">}</span> <span class="w" id="mwAjM"> </span><span class="n" id="mwAjQ">memcpy</span><span class="p" id="mwAjU">(</span><span class="n" id="mwAjY">exception_env</span><span class="p" id="mwAjc">,</span><span class="w" id="mwAjg"> </span><span class="n" id="mwAjk">my_env</span><span class="p" id="mwAjo">,</span><span class="w" id="mwAjs"> </span><span class="k" id="mwAjw">sizeof</span><span class="w" id="mwAj0"> </span><span class="n" id="mwAj4">exception_env</span><span class="p" id="mwAj8">);</span><span class="w" id="mwAkA"> </span><span class="c1" id="mwAkE">// restore exception stack</span> <span class="w" id="mwAkI"> </span><span class="n" id="mwAkM">puts</span><span class="p" id="mwAkQ">(</span><span class="s" id="mwAkU">"leaving first"</span><span class="p" id="mwAkY">);</span><span class="w" id="mwAkc"> </span><span class="c1" id="mwAkg">// never reached</span> <span class="p" id="mwAkk">}</span> <span class="k" id="mwAko">static</span><span class="w" id="mwAks"> </span><span class="kt" id="mwAkw">void</span><span class="w" id="mwAk0"> </span><span class="nf" id="mwAk4">second</span><span class="p" id="mwAk8">()</span><span class="w" id="mwAlA"> </span><span class="p" id="mwAlE">{</span> <span class="w" id="mwAlI"> </span><span class="n" id="mwAlM">puts</span><span class="p" id="mwAlQ">(</span><span class="s" id="mwAlU">"entering second"</span><span class="w" id="mwAlY"> </span><span class="p" id="mwAlc">);</span><span class="w" id="mwAlg"> </span><span class="c1" id="mwAlk">// reached</span> <span class="w" id="mwAlo"> </span><span class="n" id="mwAls">exception_type</span><span class="w" id="mwAlw"> </span><span class="o" id="mwAl0">=</span><span class="w" id="mwAl4"> </span><span class="mi" id="mwAl8">3</span><span class="p" id="mwAmA">;</span> <span class="w" id="mwAmE"> </span><span class="n" id="mwAmI">longjmp</span><span class="p" id="mwAmM">(</span><span class="n" id="mwAmQ">exception_env</span><span class="p" id="mwAmU">,</span><span class="w" id="mwAmY"> </span><span class="n" id="mwAmc">exception_type</span><span class="p" id="mwAmg">);</span><span class="w" id="mwAmk"> </span><span class="c1" id="mwAmo">// declare that the program has failed</span> <span class="w" id="mwAms"> </span><span class="n" id="mwAmw">puts</span><span class="p" id="mwAm0">(</span><span class="s" id="mwAm4">"leaving second"</span><span class="p" id="mwAm8">);</span><span class="w" id="mwAnA"> </span><span class="c1" id="mwAnE">// not reached</span> <span class="p" id="mwAnI">}</span>This program's output is:
calling first entering first calling second entering second second failed, exception type: 3; remapping to type 1 first failed, exception type: 1
Cooperative multitasking
C99 provides that longjmp is guaranteed to work only when the destination is a calling function, i.e., that the destination scope is guaranteed to be intact. Jumping to a function that has already terminated by return or longjmp is undefined. However, most implementations of longjmp do not specifically destroy local variables when performing the jump. Since the context survives until its local variables are erased, it could actually be restored by setjmp. In many environments (such as Really Simple Threads and TinyTimbers), idioms such as if(!setjmp(child_env)) longjmp(caller_env); can allow a called function to effectively pause-and-resume at a setjmp.
This is exploited by thread libraries to provide cooperative multitasking facilities without using setcontext or other fiber facilities.
Considering that setjmp to a child function will generally work unless sabotaged, and setcontext, as part of POSIX, is not required to be provided by C implementations, this mechanism may be portable where the setcontext alternative fails.
Since no exception will be generated upon overflow of one of the multiple stacks in such a mechanism, it is essential to overestimate the space required for each context, including the one containing main() and including space for any signal handlers that might interrupt regular execution. Exceeding the allocated space will corrupt the other contexts, usually with the outermost functions first. Unfortunately, systems requiring this kind of programming strategy are often also small ones with limited resources.
<span id="mwAo8"></span><span class="cp" id="mwApA">#include</span><span class="w" id="mwApE"> </span><span class="cpf" id="mwApI"><setjmp.h></span> <span class="cp" id="mwApM">#include</span><span class="w" id="mwApQ"> </span><span class="cpf" id="mwApU"><stdio.h></span> <span class="kt" id="mwApY">jmp_buf</span><span class="w" id="mwApc"> </span><span class="n" id="mwApg">mainTask</span><span class="p" id="mwApk">,</span><span class="w" id="mwApo"> </span><span class="n" id="mwAps">childTask</span><span class="p" id="mwApw">;</span> <span class="kt" id="mwAp0">void</span><span class="w" id="mwAp4"> </span><span class="nf" id="mwAp8">call_with_cushion</span><span class="p" id="mwAqA">();</span> <span class="kt" id="mwAqE">void</span><span class="w" id="mwAqI"> </span><span class="nf" id="mwAqM">child</span><span class="p" id="mwAqQ">();</span> <span class="kt" id="mwAqU">int</span><span class="w" id="mwAqY"> </span><span class="nf" id="mwAqc">main</span><span class="p" id="mwAqg">()</span><span class="w" id="mwAqk"> </span><span class="p" id="mwAqo">{</span> <span class="w" id="mwAqs"> </span><span class="k" id="mwAqw">if</span><span class="w" id="mwAq0"> </span><span class="p" id="mwAq4">(</span><span class="o" id="mwAq8">!</span><span class="n" id="mwArA">setjmp</span><span class="p" id="mwArE">(</span><span class="n" id="mwArI">mainTask</span><span class="p" id="mwArM">))</span><span class="w" id="mwArQ"> </span><span class="p" id="mwArU">{</span> <span class="w" id="mwArY"> </span><span class="n" id="mwArc">call_with_cushion</span><span class="p" id="mwArg">();</span><span class="w" id="mwArk"> </span><span class="c1" id="mwAro">// child never returns, yield</span> <span class="w" id="mwArs"> </span><span class="p" id="mwArw">}</span><span class="w" id="mwAr0"> </span><span class="c1" id="mwAr4">// execution resumes after this "}" after first time that child yields</span> <span class="w" id="mwAr8"> </span><span class="k" id="mwAsA">while</span><span class="w" id="mwAsE"> </span><span class="p" id="mwAsI">(</span><span class="mi" id="mwAsM">1</span><span class="p" id="mwAsQ">)</span><span class="w" id="mwAsU"> </span><span class="p" id="mwAsY">{</span> <span class="w" id="mwAsc"> </span><span class="n" id="mwAsg">printf</span><span class="p" id="mwAsk">(</span><span class="s" id="mwAso">"Parent</span><span class="se" id="mwAss">\n</span><span class="s" id="mwAsw">"</span><span class="p" id="mwAs0">);</span> <span class="w" id="mwAs4"> </span> <span class="w" id="mwAs8"> </span><span class="k" id="mwAtA">if</span><span class="w" id="mwAtE"> </span><span class="p" id="mwAtI">(</span><span class="o" id="mwAtM">!</span><span class="n" id="mwAtQ">setjmp</span><span class="p" id="mwAtU">(</span><span class="n" id="mwAtY">mainTask</span><span class="p" id="mwAtc">))</span> <span class="w" id="mwAtg"> </span><span class="n" id="mwAtk">longjmp</span><span class="p" id="mwAto">(</span><span class="n" id="mwAts">childTask</span><span class="p" id="mwAtw">,</span><span class="w" id="mwAt0"> </span><span class="mi" id="mwAt4">1</span><span class="p" id="mwAt8">);</span><span class="w" id="mwAuA"> </span><span class="c1" id="mwAuE">// yield - note that this is undefined under C99</span> <span class="w" id="mwAuI"> </span><span class="p" id="mwAuM">}</span> <span class="p" id="mwAuQ">}</span> <span class="kt" id="mwAuU">void</span><span class="w" id="mwAuY"> </span><span class="nf" id="mwAuc">call_with_cushion</span><span class="p" id="mwAug">()</span><span class="w" id="mwAuk"> </span><span class="p" id="mwAuo">{</span> <span class="w" id="mwAus"> </span><span class="kt" id="mwAuw">char</span><span class="w" id="mwAu0"> </span><span class="n" id="mwAu4">space</span><span class="p" id="mwAu8">[</span><span class="mi" id="mwAvA">1000</span><span class="p" id="mwAvE">];</span><span class="w" id="mwAvI"> </span><span class="c1" id="mwAvM">// Reserve enough space for main to run</span> <span class="w" id="mwAvQ"> </span><span class="n" id="mwAvU">space</span><span class="p" id="mwAvY">[</span><span class="mi" id="mwAvc">999</span><span class="p" id="mwAvg">]</span><span class="w" id="mwAvk"> </span><span class="o" id="mwAvo">=</span><span class="w" id="mwAvs"> </span><span class="mi" id="mwAvw">1</span><span class="p" id="mwAv0">;</span><span class="w" id="mwAv4"> </span><span class="c1" id="mwAv8">// Do not optimize array out of existence</span> <span class="w" id="mwAwA"> </span><span class="n" id="mwAwE">child</span><span class="p" id="mwAwI">();</span> <span class="p" id="mwAwM">}</span> <span class="kt" id="mwAwQ">void</span><span class="w" id="mwAwU"> </span><span class="nf" id="mwAwY">child</span><span class="p" id="mwAwc">()</span><span class="w" id="mwAwg"> </span><span class="p" id="mwAwk">{</span> <span class="w" id="mwAwo"> </span><span class="k" id="mwAws">while</span><span class="w" id="mwAww"> </span><span class="p" id="mwAw0">(</span><span class="mi" id="mwAw4">1</span><span class="p" id="mwAw8">)</span><span class="w" id="mwAxA"> </span><span class="p" id="mwAxE">{</span> <span class="w" id="mwAxI"> </span><span class="n" id="mwAxM">printf</span><span class="p" id="mwAxQ">(</span><span class="s" id="mwAxU">"Child loop begin</span><span class="se" id="mwAxY">\n</span><span class="s" id="mwAxc">"</span><span class="p" id="mwAxg">);</span> <span class="w" id="mwAxk"> </span> <span class="w" id="mwAxo"> </span><span class="k" id="mwAxs">if</span><span class="w" id="mwAxw"> </span><span class="p" id="mwAx0">(</span><span class="o" id="mwAx4">!</span><span class="n" id="mwAx8">setjmp</span><span class="p" id="mwAyA">(</span><span class="n" id="mwAyE">childTask</span><span class="p" id="mwAyI">))</span> <span class="w" id="mwAyM"> </span><span class="n" id="mwAyQ">longjmp</span><span class="p" id="mwAyU">(</span><span class="n" id="mwAyY">mainTask</span><span class="p" id="mwAyc">,</span><span class="w" id="mwAyg"> </span><span class="mi" id="mwAyk">1</span><span class="p" id="mwAyo">);</span><span class="w" id="mwAys"> </span><span class="c1" id="mwAyw">// yield - invalidates childTask in C99</span> <span class="w" id="mwAy0"> </span><span class="n" id="mwAy4">printf</span><span class="p" id="mwAy8">(</span><span class="s" id="mwAzA">"Child loop end</span><span class="se" id="mwAzE">\n</span><span class="s" id="mwAzI">"</span><span class="p" id="mwAzM">);</span> <span class="w" id="mwAzQ"> </span><span class="k" id="mwAzU">if</span><span class="w" id="mwAzY"> </span><span class="p" id="mwAzc">(</span><span class="o" id="mwAzg">!</span><span class="n" id="mwAzk">setjmp</span><span class="p" id="mwAzo">(</span><span class="n" id="mwAzs">childTask</span><span class="p" id="mwAzw">))</span> <span class="w" id="mwAz0"> </span><span class="n" id="mwAz4">longjmp</span><span class="p" id="mwAz8">(</span><span class="n" id="mwA0A">mainTask</span><span class="p" id="mwA0E">,</span><span class="w" id="mwA0I"> </span><span class="mi" id="mwA0M">1</span><span class="p" id="mwA0Q">);</span><span class="w" id="mwA0U"> </span><span class="c1" id="mwA0Y">// yield - invalidates childTask in C99</span> <span class="w" id="mwA0c"> </span><span class="p" id="mwA0g">}</span> <span class="w" id="mwA0k"> </span><span class="cm" id="mwA0o">/* Don't return. Instead we should set a flag to indicate that main()</span> <span class="cm" id="mwA0s"> should stop yielding to us and then longjmp(mainTask, 1) */</span> <span class="p" id="mwA0w">}</span>
