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