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