From: "H.Yamamoto" Date: 2005-08-19T19:13:35+09:00 Subject: [ruby-dev:26837] Re: cannot check EOF of pipe on windows 山本です。 >タイミングっぽいです。 > > io.write %q{ > p 1 > print 'xy' > sleep 0 > } > >と最後にsleep 0を入れると最後まで通るようになりました。 ですね。こうすると、こんどは全く読み込めなくなりました。 IO.popen('ruby', 'r+'){|io| io.write %q{ p 1 print 'xy' } io.close_write sleep 1 while c = io.read(1) p c p io.eof? end } 読めなくなるタイミングというのが、ちょうど read で ERROR_NETNAME_DELETED が返るタイミングのようなので、 これを無視してはいけないような雰囲気です。 # io.close_write が何か良からぬことをしてるんでしょうか >想像ですが、ソケットの場合送信側と受信側のバッファが分かれてい >て、プロセスの終了かWSACleanup()で送信側のバッファに残っていて >も捨てられてしまうんじゃないでしょうか。ERROR_NETNAME_DELETEDは >ソケットにおいてERROR_BROKEN_PIPEに相当しているのかもしれません。 http://www.kt.rim.or.jp/~ksk/wskfaq-ja/articles/debugging-tcp.html を読んだときに私もそうじゃないかと思ったのですが、調べてみると 子プロセスは親プロセスより長生きしているようなので、この場合は 違うのかもしれません。(断言はできませんが) puts Process.pid IO.popen('ruby', 'r+'){|io| io.write %q{ p 1 print 'xy' } io.close_write sleep 1 while c = io.read(1) p c p io.eof? end } Index: win32.c =================================================================== RCS file: /src/ruby/win32/win32.c,v retrieving revision 1.164 diff -u -w -b -p -r1.164 win32.c --- win32.c 18 Aug 2005 02:07:28 -0000 1.164 +++ win32.c 19 Aug 2005 10:02:34 -0000 @@ -180,6 +180,12 @@ static struct { { WSAENOTEMPTY, ENOTEMPTY } }; +static void +debug(const char *msg) +{ + printf("%s (%d)\n", msg, getpid()); +} + static int map_errno(DWORD winerr) { @@ -1992,6 +1998,14 @@ rb_w32_select(int nfds, fd_set *rd, fd_s } static void +CleanSockets(void) +{ + debug("WSACleanup"); + + WSACleanup(); +} + +static void StartSockets(void) { WORD version; @@ -2007,7 +2021,7 @@ StartSockets(void) if (LOBYTE(retdata.wVersion) != 2) rb_fatal("could not find version 2 of winsock dll\n"); - atexit((void (*)(void)) WSACleanup); + atexit(CleanSockets); main_thread.handle = GetCurrentThreadHandle(); main_thread.id = GetCurrentThreadId(); @@ -2279,6 +2293,8 @@ open_ifs_socket(int af, int type, int pr int error_code; SOCKET out = INVALID_SOCKET; +debug("open_ifs_socket"); + if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) { error_code = WSAGetLastError(); if (error_code == WSAENOBUFS) { @@ -3286,22 +3302,28 @@ catch_interrupt(void) CHECK_INTS; } -#if defined __BORLANDC__ || defined _WIN32_WCE -#undef read int -read(int fd, void *buf, size_t size) +rb_w32_read(int fd, void *buf, size_t size) { + int oerr = errno; int trap_immediate = rb_trap_immediate; int ret = _read(fd, buf, size); - if ((ret < 0) && (errno == EPIPE)) { - errno = 0; +#if defined __BORLANDC__ || defined _WIN32_WCE + if (ret < 0 && errno == EPIPE) { + errno = oerr; + ret = 0; + } +#endif +/* + if (ret < 0 && GetLastError() == ERROR_NETNAME_DELETED) { + errno = oerr; ret = 0; } +*/ rb_trap_immediate = trap_immediate; catch_interrupt(); return ret; } -#endif #undef fgetc int @@ -3506,6 +3528,9 @@ rb_w32_fclose(FILE *fp) } _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); fclose(fp); + + debug("closesocket"); + if (closesocket(sock) == SOCKET_ERROR) { errno = map_errno(WSAGetLastError()); return -1; @@ -3524,6 +3549,9 @@ rb_w32_close(int fd) } _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); _close(fd); + + debug("closesocket"); + if (closesocket(sock) == SOCKET_ERROR) { errno = map_errno(WSAGetLastError()); return -1; E:\ruby-cvs\win32>ruby \z.rb 1036 open_ifs_socket (1036) open_ifs_socket (1036) closesocket (1036) /z.rb:12:in `read': Invalid argument (Errno::EINVAL) from /z.rb:12 from /z.rb:4 WSACleanup (1036) WSACleanup (1164)