mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* win32/win32.c (rb_w32_select): fixed deadlock bug.
because select(2) modifies its fd_set arguments, it must be restored sometimes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9198 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
f34cec631e
commit
f2107f2ec1
2 changed files with 43 additions and 33 deletions
|
@ -1,3 +1,9 @@
|
|||
Sat Sep 17 20:58:56 2005 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
||||
|
||||
* win32/win32.c (rb_w32_select): fixed deadlock bug.
|
||||
because select(2) modifies its fd_set arguments, it must be
|
||||
restored sometimes.
|
||||
|
||||
Sat Sep 17 14:54:40 2005 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
||||
|
||||
* test/ruby/test_readpartial.rb (test_open_pipe, test_with_stdio):
|
||||
|
|
|
@ -1906,11 +1906,11 @@ rb_w32_fdisset(int fd, fd_set *set)
|
|||
|
||||
static int NtSocketsInitialized = 0;
|
||||
|
||||
static void
|
||||
static int
|
||||
extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
|
||||
{
|
||||
int s = 0;
|
||||
if (!src) return;
|
||||
if (!src || !dst) return 0;
|
||||
|
||||
while (s < src->fd_count) {
|
||||
SOCKET fd = src->fd_array[s];
|
||||
|
@ -1931,6 +1931,8 @@ extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
|
|||
}
|
||||
else s++;
|
||||
}
|
||||
|
||||
return dst->fd_count;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2047,11 +2049,12 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
|||
long r;
|
||||
fd_set pipe_rd;
|
||||
fd_set cons_rd;
|
||||
fd_set unknown_rd;
|
||||
fd_set unknown_wr;
|
||||
fd_set else_rd;
|
||||
fd_set else_wr;
|
||||
#ifdef USE_INTERRUPT_WINSOCK
|
||||
fd_set trap;
|
||||
#endif /* USE_INTERRUPT_WINSOCK */
|
||||
int nonsock = 0;
|
||||
|
||||
if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
|
||||
errno = EINVAL;
|
||||
|
@ -2061,23 +2064,17 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
|||
StartSockets();
|
||||
}
|
||||
|
||||
else_rd.fd_count = 0;
|
||||
nonsock += extract_fd(&else_rd, rd, is_not_socket);
|
||||
|
||||
pipe_rd.fd_count = 0;
|
||||
extract_fd(&pipe_rd, &else_rd, is_pipe); // should not call is_pipe for socket
|
||||
|
||||
cons_rd.fd_count = 0;
|
||||
unknown_rd.fd_count = 0;
|
||||
unknown_wr.fd_count = 0;
|
||||
extract_fd(&cons_rd, &else_rd, is_console); // ditto
|
||||
|
||||
extract_fd(&unknown_rd, rd, is_not_socket); /* must exclude socket first! */
|
||||
extract_fd(&unknown_wr, wr, is_not_socket); /* must exclude socket first! */
|
||||
extract_fd(&pipe_rd, &unknown_rd, is_pipe); /* don't call is_pipe for socket! */
|
||||
extract_fd(&cons_rd, &unknown_rd, is_console); /* probably ditto */
|
||||
|
||||
if (unknown_rd.fd_count + unknown_wr.fd_count) {
|
||||
// assume unknown handles are always readable/writable
|
||||
// fake read/write fd_set and return value
|
||||
if (rd) *rd = unknown_rd;
|
||||
if (wr) *wr = unknown_wr;
|
||||
return unknown_rd.fd_count + unknown_wr.fd_count;
|
||||
}
|
||||
else_wr.fd_count = 0;
|
||||
nonsock += extract_fd(&else_wr, wr, is_not_socket);
|
||||
|
||||
r = 0;
|
||||
if (rd && rd->fd_count > r) r = rd->fd_count;
|
||||
|
@ -2097,30 +2094,37 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
|||
#endif /* USE_INTERRUPT_WINSOCK */
|
||||
|
||||
RUBY_CRITICAL(
|
||||
if (pipe_rd.fd_count || cons_rd.fd_count) {
|
||||
if (nonsock) {
|
||||
struct timeval rest;
|
||||
struct timeval wait;
|
||||
struct timeval zero;
|
||||
if (timeout) rest = *timeout;
|
||||
wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms
|
||||
zero.tv_sec = 0; zero.tv_usec = 0; // poling
|
||||
do {
|
||||
fd_set buf; buf.fd_count = 0;
|
||||
// pipe
|
||||
extract_fd(&buf, &pipe_rd, is_readable_pipe);
|
||||
// console
|
||||
extract_fd(&buf, &cons_rd, is_readable_console);
|
||||
// socket
|
||||
if (buf.fd_count) {
|
||||
r = do_select(nfds, rd, wr, ex, &wait);
|
||||
if (r >= 0) {
|
||||
r += buf.fd_count;
|
||||
extract_fd(rd, &buf, NULL); // move all `buf' contents into `rd'.
|
||||
}
|
||||
// XXX: should I ignore socket error and returns readable pipe/console?
|
||||
// this is safe because handle is moved, function returns anway.
|
||||
extract_fd(&else_rd, &pipe_rd, is_readable_pipe);
|
||||
extract_fd(&else_rd, &cons_rd, is_readable_console);
|
||||
|
||||
if (else_rd.fd_count || else_wr.fd_count) {
|
||||
r = do_select(nfds, rd, wr, ex, &zero);
|
||||
if (r < 0) break; // XXX: should I ignore error and return signaled handles?
|
||||
r += extract_fd(rd, &else_rd, NULL);
|
||||
r += extract_fd(wr, &else_wr, NULL);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
fd_set orig_rd;
|
||||
fd_set orig_wr;
|
||||
fd_set orig_ex;
|
||||
if (rd) orig_rd = *rd;
|
||||
if (wr) orig_wr = *wr;
|
||||
if (ex) orig_ex = *ex;
|
||||
r = do_select(nfds, rd, wr, ex, &wait);
|
||||
if (r) break; // readable or error (not pending)
|
||||
if (r) break; // signaled or error
|
||||
if (rd) *rd = orig_rd;
|
||||
if (wr) *wr = orig_wr;
|
||||
if (ex) *ex = orig_ex;
|
||||
}
|
||||
} while (!timeout || subst(&rest, &wait));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue