読者です 読者をやめる 読者になる 読者になる

セミコルーチンの実装(x86 only)

手っ取り早く、手ぬきで実装するとこんな感じになります。
他のマシンで実行したい場合は、jmp_bufの中身をよく観察して、適切なインデックスに突っ込めば、大抵OKです。

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

typedef struct co {
    void (*proc)(void);
    jmp_buf jb;
} co_t;

static jmp_buf org;
static co_t *cur = NULL;
static void *del = NULL;

static void
co_run(void)
{
    (*cur->proc)();
    del = cur;
    longjmp(org, 1);
}

static void *
co_create(void (*proc)(void), size_t size)
{
    co_t *co = malloc(size + sizeof(co_t));
    setjmp(co->jb);
    co->jb[0] = (typeof(co->jb[0])) co_run;
    co->jb[2] = (typeof(co->jb[0])) (char *)(co + 1) + size;
    co->proc = proc;
    cur = co;
    return co;
}

static void
co_suspend(void)
{
    if (setjmp(cur->jb) == 0)
        longjmp(org, 1);
}

static int
co_resume(void *obj)
{
    co_t *co = (co_t *)obj;
    if (setjmp(org) == 0) {
        longjmp(co->jb, 1);
    } else if (del) {
        free(del);
        del = NULL;
        return 0;
    }
    return 1;
}

static void
co(void)
{
    int i;

    for (i = 0; i < 20; i++) {
        printf("%d\n", i);
        co_suspend();
    }
}

int
main(int argc, char **argv)
{
    void *obj;

    obj = co_create(co, 8000);

    while (co_resume(obj))
        ;

    return EXIT_SUCCESS;
}