Portable Coroutine Library (PCL)

前回までのあらすじ: GNU Pth イイ!と思ったけどよく見ると MinGW をサポートしてなかった。

で、数時間の迷走の結果 (CreateFiberは Win95 ダメだとと知ってみたり、 WINE の CreateFiber を見たり、アセンブラ読んでみたり、自分で作ろうとしてスタックが壊れたり) PCL というのを見つけました。

http://xmailserver.org/libpcl.html

ポータブルという割には MacOSXMinGWCygwin もダメだったんですけど、 Io から jmp_buf に esp と eip を保存しているらしいコードをひっこぬいてきたら、 MacOSX でも MinGW でも動くようになりました。 Solaris はダメみたいで、 Cygwin, Zaurus, FreeBSD, NetBSD, VC あたりは動くはず…今度確認します。

これがパッチ。

http://shinh.skr.jp/dat_dir/pcl_ioarch.patch

ちなみに GPL なのが人によっては困りどころかもしれません。 GPL イヤンな人は IoVM の Scheduler.[ch] と Coro.[ch] あたりでなんとかなるかもしれません。

pcl.d

extern (C) {
    alias void* coroutine_t;
    coroutine_t co_create(void (*func)(void *),
                          void *data, void *stack, int size);
    void co_delete(coroutine_t coro);
    void co_call(coroutine_t coro);
    void co_resume();
    void co_exit_to(coroutine_t coro);
    void co_exit();
    coroutine_t co_current();
}

test_pcl.c

#include 

#include 

#define CO_STACK_SIZE (8 * 1024)

void spawn1(void* arg) {
    int i = 0;
    int fiber = (int)arg;
    printf("1 %d %d\n", fiber, i+=2);
    co_resume();
    printf("4 %d %d\n", fiber, i+=2);
    co_resume();
}

void spawn2(void* arg) {
    int fiber = (int)arg;
    int i = 0;
    printf("2 %d %d\n", fiber, i++);
    co_resume();
    printf("5 %d %d\n", fiber, i++);
    co_resume();
}

int main() {
    coroutine_t co1, co2;

    co1 = co_create(&spawn1, (void*)1, NULL, CO_STACK_SIZE);
    co2 = co_create(&spawn2, (void*)2, NULL, CO_STACK_SIZE);

    printf("ok?\n");

    co_call(co1);
    co_call(co2);
    printf("3\n");
    co_call(co1);
    co_call(co2);

    co_delete(co1);
    co_delete(co2);
}
なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h