Starting from the example in the GNU C Library info pages on System V contexts, I cooked up a starting point for continuations in C++. Usage is simple:
#include <stdio.h> #include "continuation.h" static void increment (int *n) { printf ("Nothing interesting: %d\n", *n); ++*n; } int main (void) { int initial_value = 0; continuation main_uc; continuation inc0_uc (main_uc, increment, &initial_value); continuation inc1_uc (inc0_uc, increment, &initial_value); main_uc.switch_to (inc1_uc); printf ("I'm back: %d\n", initial_value); return 0; }
Program output is as expected:
Nothing interesting: 0 Nothing interesting: 1 I'm back: 2
That is, the first frame runs increment
; the second frame does the same; and the last frame runs main
from where it left off after jumping to the first frame: a continuation.
The header:
#ifndef _CONTINUATION_H #define _CONTINUATION_H #include <stdexcept> #include <errno.h> #include <string.h> #include <ucontext.h> // Tricky to work out without cpu-os-specific information: #define STACK_SIZE 4096 class continuation : public ucontext_t { char stack[STACK_SIZE]; public: continuation () { initialize (); } continuation (continuation &next) { initialize (); uc_link = &next; } continuation (continuation &next, void (*lambda) (void)) { initialize (); uc_link = &next; set_lambda (lambda); } template<typename T0> continuation (continuation &next, void (*lambda) (T0), T0 t0) { initialize (); uc_link = &next; set_lambda (lambda, t0); } int switch_to (continuation &next) { return swapcontext (this, &next); } private: void initialize () { if (getcontext (this) < 0) throw std::runtime_error (strerror (errno)); uc_stack.ss_sp = stack; uc_stack.ss_size = sizeof stack; } void set_lambda (void (*lambda) ()) { makecontext (this, lambda, 0); } template<typename T0> void set_lambda (void (*lambda) (T0), T0 t0) { makecontext (this, (void (*) (void)) (lambda), 1, t0); } }; #endif /* _CONTINUATION_H */
No comments:
Post a Comment