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コアって作れんのかな? 簡単に作れるならいいけど、やっぱり改造が必要になるかねー。