トップ 最新

kumaryu日記

2007-09-14 ねねね眠い

_ ねむいぜー

こんな時間まで起きてると眠いぜー。

しかし大富豪サーバー作り終わらねぇ…。

_ [Ruby] Win32

やられた。

大富豪サーバーはずっとMac上で作ってて、まあ普通に動いたからWindowsでも大丈夫だろうとmingw版で動かしてみたんだが。

まあものの見事に動かないわけで。

スレッドの動作が違うのかなー、と思ったんだが、ところどころsleep入れてもちゃんと動かない。

で、どうもどこかで全体が止まっちゃってるみたいなんだが。

と、ああ、そういえばWin32版はIOがスレッドだけじゃなくて全体をブロックするんだっけ、と調べたらやっぱりそうみたい。

しかし4クライアントとパイプで通信してるんだが、パイプから読み込めるかどうかはselectで判定してるはずだが…?

ってWin32版ではselectはソケットにしか効かないのか。つかえねー。

で、他にノンブロックでパイプから読み取る方法は…え、ないの?

Win32版だとブロックのみですか?

いろいろ探し回ったが、どうもそうみたい。

まあ出来ないものは出来ないので仕方無い…って言って済むもんじゃないしなぁ。

Win32API使えばなんとかならんの? と思って探したらPeekNamedPipeとかあるじゃないですか。これで何バイト読めるか取得できるらしい。selectより便利だな。

そんなわけで無理矢理パイプのread側にPeekNamedPipeを呼び出す拡張モジュールを作ってやってみたんだが、やっぱり動作がおかしいな…。何バイト読めるか取得した後rubyレベルのreadを使ってるのがまずいのか?

PeekNamedPipeしたあとそのままReadFileで取得してみたら上手く行った。 大丈夫なのか? と思わんこともないが、rubyのreadと混ぜてはないんでまあ多分大丈夫でしょう。

プロセス周りとか変なIO周りとかはWindowsではどうしても別物になっちゃうよなー。ほんとMacはUnixで楽だわ。

cygwinを使うという手も考えたけど、cygwin慣れてないんでこれまた変なところで嵌りそうなんでやめた。というかexerbでexe化するつもりだからcygwin使っても意味ないことには今気付いた。

まあ動いたのでなにより…。これからexe化しよう。

とりあえず作ったのはこんなもん。

#include <ruby.h>
#include <rubyio.h>

static VALUE s_peekpipe(VALUE self, VALUE vpipe)
{
  OpenFile* vfd;
  GetOpenFile(vpipe, vfd);
  FILE* fd = GetReadFile(vfd);
  long osf = get_osfhandle(fileno(fd));
  DWORD avail = 0;
  BOOL res = PeekNamedPipe((HANDLE)osf, NULL, 0, NULL, &avail, NULL);
  if (!res) {
    return Qnil;
  }
  else if (avail>0) {
    DWORD read_bytes = 0;
    char* buf = (char*)malloc(avail);
    ReadFile((HANDLE)osf, buf, avail, &read_bytes, NULL);
    VALUE res = rb_str_new(buf, read_bytes);
    free(buf);
    return res;
  }
  else {
    return rb_str_new(0, 0);
  }
}

void Init_peekpipe()
{
  rb_define_global_function("peekpipe", s_peekpipe, 1);
}

pipeが閉じてるとかでエラーが出ればnilを返してそれ以外ではなんか文字列を返す。Windowsでgcc専用だね。VC++でも動くかもしれんけどやってないのでなんとも。

そういやRikoとかそのうち1.9専用にしようかと思ったんだが、exerbの1.9コアって作れんのかな? 簡単に作れるならいいけど、やっぱり改造が必要になるかねー。