summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorocean <ocean@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-09-17 12:20:07 +0000
committerocean <ocean@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-09-17 12:20:07 +0000
commitf2107f2ec1cfcc9e86bb69949faf21e161516076 (patch)
tree2c1a29d9d4feaa6956b79f01ef09a0cbb8effaac /win32
parentf34cec631eced2302f34124d3a3e9902ac3da5a3 (diff)
* 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
Diffstat (limited to 'win32')
-rw-r--r--win32/win32.c70
1 files changed, 37 insertions, 33 deletions
diff --git a/win32/win32.c b/win32/win32.c
index 3ca7380550..da0fa3c069 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -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;
- cons_rd.fd_count = 0;
- unknown_rd.fd_count = 0;
- unknown_wr.fd_count = 0;
+ extract_fd(&pipe_rd, &else_rd, is_pipe); // should not call is_pipe for socket
- 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 */
+ cons_rd.fd_count = 0;
+ extract_fd(&cons_rd, &else_rd, is_console); // 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));
}