From: "U.Nakamura" Date: 2008-07-12T04:32:40+09:00 Subject: [ruby-dev:35448] Re: [Bug:trunk] Thread#kill cannot break BLOCKING_REGION() on windows こんにちは、なかむら(う)です。 In message "[ruby-dev:35446] [Bug:trunk] Thread#kill cannot break BLOCKING_REGION() on windows" on Jul.12,2008 01:56:54, wrote: | Windows(除cygwin)では、外部からBLOCKING_REGION()を中断させる | ことができないので、あるスレッドがBLOCKING_REGION()に入ってい | る場合、そのスレッドをThread#killで終了されることができません。 この問題は解決してないんですが、 | 例: | require "socket" | s = TCPServer.new(0) | t = Thread.new{s.accept} | sleep 1 | t.kill | t.join # <= acceptがBLOCKING_REGION()内で処理されるため、 | # ここで永久に待ち状態となる この例に限定すると、以下のパッチで解決します。 # 例がacceptなのでacceptだけ対処しています。 思うに、socket.soからrb_thread_blocking_region()を呼び出すよ り、このパッチのように、io.cでやってるのと同様、ブロックしう る関数の呼び出しの前に読み書き可能のチェックを行うべきではな いでしょうか。 Index: ext/socket/socket.c =================================================================== --- ext/socket/socket.c (revision 18034) +++ ext/socket/socket.c (working copy) @@ -1525,32 +1525,16 @@ s_accept_nonblock(VALUE klass, rb_io_t * return init_sock(rb_obj_alloc(klass), fd2); } -struct accept_arg { - int fd; - struct sockaddr *sockaddr; - socklen_t *len; -}; - -static VALUE -accept_blocking(void *data) -{ - struct accept_arg *arg = data; - return (VALUE)accept(arg->fd, arg->sockaddr, arg->len); -} - static VALUE s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len) { int fd2; int retry = 0; - struct accept_arg arg; rb_secure(3); - arg.fd = fd; - arg.sockaddr = sockaddr; - arg.len = len; retry: - fd2 = (int)BLOCKING_REGION(accept_blocking, &arg); + rb_thread_wait_fd(fd); + fd2 = accept(fd, sockaddr, len); if (fd2 < 0) { switch (errno) { case EMFILE: # 以下は、以上の話と直接関係はないなかださん宛の私信: # # だいぶ前にちらっと話したことがあるように、defファイルで言う # select@20=_rb_w32_select@20 # みたいな奴が拡張ライブラリから正しく参照されず、直接ws2_32.dll # 向きになってしまうことがあるようです。 # msvcrt-ruby190.dllが更新されずにsocket.soだけ更新されるよう # なパターンで再現したのですが、理由はさっぱりわかりません... # なんか心当たりはありますか? それでは。 -- U.Nakamura