mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* win32/win32.c (rb_w32_select): select for socket didn't work.
this caused deadlock in drb test. this happened because GetFileType for socket handle returns FILE_TYPE_PIPE. Of course, it's not a pipe. So socket handle didn't reach winsock's select function. * win32/win32.c (rb_w32_select): read for pipe still kept brocking even if writer handle was closed. r,w = IO.pipe Thread.new { sleep 3; puts "------- 1" w.puts("foo") sleep 3; puts "------- 2" w.puts("boo") sleep 3; puts "------- 3" w.close } until r.eof? # should break by w.close but didn't. puts r.gets end * win32/win32.c (rb_w32_select): temprary reverted console support but it'll be back soon. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9192 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
762ed0d68c
commit
846b1c35e5
2 changed files with 128 additions and 222 deletions
28
ChangeLog
28
ChangeLog
|
@ -1,3 +1,31 @@
|
||||||
|
Sat Sep 17 11:24:16 2005 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
||||||
|
|
||||||
|
* win32/win32.c (rb_w32_select): select for socket didn't work.
|
||||||
|
this caused deadlock in drb test. this happened because GetFileType
|
||||||
|
for socket handle returns FILE_TYPE_PIPE. Of course, it's not a
|
||||||
|
pipe. So socket handle didn't reach winsock's select function.
|
||||||
|
|
||||||
|
* win32/win32.c (rb_w32_select): read for pipe still kept brocking
|
||||||
|
even if writer handle was closed.
|
||||||
|
|
||||||
|
r,w = IO.pipe
|
||||||
|
|
||||||
|
Thread.new {
|
||||||
|
sleep 3; puts "------- 1"
|
||||||
|
w.puts("foo")
|
||||||
|
sleep 3; puts "------- 2"
|
||||||
|
w.puts("boo")
|
||||||
|
sleep 3; puts "------- 3"
|
||||||
|
w.close
|
||||||
|
}
|
||||||
|
|
||||||
|
until r.eof? # should break by w.close but didn't.
|
||||||
|
puts r.gets
|
||||||
|
end
|
||||||
|
|
||||||
|
* win32/win32.c (rb_w32_select): temprary reverted console support
|
||||||
|
but it'll be back soon.
|
||||||
|
|
||||||
Sat Sep 17 10:42:13 2005 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
|
Sat Sep 17 10:42:13 2005 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
|
||||||
|
|
||||||
* ext/tk/lib/multi-tk.rb: MultiTkIp#eval_string and bg_eval_string
|
* ext/tk/lib/multi-tk.rb: MultiTkIp#eval_string and bg_eval_string
|
||||||
|
|
322
win32/win32.c
322
win32/win32.c
|
@ -1906,226 +1906,130 @@ rb_w32_fdisset(int fd, fd_set *set)
|
||||||
|
|
||||||
static int NtSocketsInitialized = 0;
|
static int NtSocketsInitialized = 0;
|
||||||
|
|
||||||
static int
|
static void
|
||||||
collect_file_fd(fd_set *set, fd_set *fileset)
|
extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
|
||||||
{
|
{
|
||||||
int idx;
|
int s = 0;
|
||||||
|
if (!src) return;
|
||||||
|
|
||||||
fileset->fd_count = 0;
|
while (s < src->fd_count) {
|
||||||
if (!set)
|
SOCKET fd = src->fd_array[s];
|
||||||
return 0;
|
|
||||||
for (idx = 0; idx < set->fd_count; idx++) {
|
|
||||||
SOCKET fd = set->fd_array[idx];
|
|
||||||
|
|
||||||
if (!is_socket(fd)) {
|
if (!func || (*func)(fd)) { /* move it to dst */
|
||||||
int i;
|
int d;
|
||||||
|
|
||||||
for (i = 0; i < fileset->fd_count; i++) {
|
for (d = 0; d < dst->fd_count; d++) {
|
||||||
if (fileset->fd_array[i] == fd) {
|
if (dst->fd_array[d] == fd) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (i == fileset->fd_count) {
|
if (d == dst->fd_count && dst->fd_count < FD_SETSIZE) {
|
||||||
if (fileset->fd_count < FD_SETSIZE) {
|
dst->fd_array[dst->fd_count++] = fd;
|
||||||
fileset->fd_array[i] = fd;
|
|
||||||
fileset->fd_count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
memmove(
|
||||||
|
&src->fd_array[s],
|
||||||
|
&src->fd_array[s+1],
|
||||||
|
sizeof(src->fd_array[0]) * (--src->fd_count - s));
|
||||||
}
|
}
|
||||||
|
else s++;
|
||||||
}
|
}
|
||||||
return fileset->fd_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
extract_pipe_fd(fd_set *set, fd_set *fileset)
|
is_not_socket(SOCKET sock)
|
||||||
{
|
{
|
||||||
int idx;
|
return !is_socket(sock);
|
||||||
|
|
||||||
fileset->fd_count = 0;
|
|
||||||
if (!set)
|
|
||||||
return 0;
|
|
||||||
for (idx = 0; idx < set->fd_count; idx++) {
|
|
||||||
DWORD type;
|
|
||||||
int fd = set->fd_array[idx];
|
|
||||||
RUBY_CRITICAL(type = GetFileType((HANDLE)fd));
|
|
||||||
|
|
||||||
if (type == FILE_TYPE_PIPE) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < fileset->fd_count; i++) {
|
|
||||||
if (fileset->fd_array[i] == fd) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == fileset->fd_count) {
|
|
||||||
if (fileset->fd_count < FD_SETSIZE) {
|
|
||||||
fileset->fd_array[i] = fd;
|
|
||||||
fileset->fd_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = idx; i < set->fd_count - 1; i++) {
|
|
||||||
set->fd_array[i] = set->fd_array[i + 1];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
set->fd_count--;
|
|
||||||
idx--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fileset->fd_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
peek_pipe(fd_set *set, fd_set *fileset)
|
is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */
|
||||||
{
|
{
|
||||||
int idx;
|
int ret;
|
||||||
|
|
||||||
fileset->fd_count = 0;
|
RUBY_CRITICAL(
|
||||||
for (idx = 0; idx < set->fd_count; idx++) {
|
ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE)
|
||||||
DWORD n;
|
);
|
||||||
int fd = set->fd_array[idx];
|
|
||||||
if (PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &n, NULL) && n > 0) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < fileset->fd_count; i++) {
|
return ret;
|
||||||
if (fileset->fd_array[i] == fd) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == fileset->fd_count) {
|
|
||||||
if (fileset->fd_count < FD_SETSIZE) {
|
|
||||||
fileset->fd_array[i] = fd;
|
|
||||||
fileset->fd_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileset->fd_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
extract_console_fd(fd_set *set, fd_set *fileset)
|
is_readable_pipe(SOCKET sock) /* call this for pipe only */
|
||||||
{
|
{
|
||||||
int idx;
|
int ret;
|
||||||
|
DWORD n = 0;
|
||||||
|
|
||||||
fileset->fd_count = 0;
|
RUBY_CRITICAL(
|
||||||
if (!set)
|
if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
|
||||||
return 0;
|
ret = (n > 0);
|
||||||
for (idx = 0; idx < set->fd_count; idx++) {
|
|
||||||
BOOL ret;
|
|
||||||
static INPUT_RECORD ir;
|
|
||||||
DWORD n;
|
|
||||||
int fd = set->fd_array[idx];
|
|
||||||
RUBY_CRITICAL(ret = PeekConsoleInput((HANDLE)fd, &ir, 1, &n));
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < fileset->fd_count; i++) {
|
|
||||||
if (fileset->fd_array[i] == fd) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == fileset->fd_count) {
|
|
||||||
if (fileset->fd_count < FD_SETSIZE) {
|
|
||||||
fileset->fd_array[i] = fd;
|
|
||||||
fileset->fd_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = idx; i < set->fd_count - 1; i++) {
|
|
||||||
set->fd_array[i] = set->fd_array[i + 1];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
set->fd_count--;
|
|
||||||
idx--;
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
return fileset->fd_count;
|
ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static long
|
||||||
peek_console(fd_set *set, fd_set *fileset)
|
do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
||||||
|
struct timeval *timeout)
|
||||||
{
|
{
|
||||||
int idx;
|
long r = 0;
|
||||||
INPUT_RECORD ir;
|
|
||||||
|
|
||||||
fileset->fd_count = 0;
|
if (nfds == 0 && timeout) {
|
||||||
for (idx = 0; idx < set->fd_count; idx++) {
|
Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
|
||||||
DWORD n;
|
}
|
||||||
int fd = set->fd_array[idx];
|
else {
|
||||||
if (PeekConsoleInput((HANDLE)fd, &ir, 1, &n) && n > 0) {
|
r = select(nfds, rd, wr, ex, timeout);
|
||||||
if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
|
if (r == SOCKET_ERROR) {
|
||||||
ir.Event.KeyEvent.uChar.AsciiChar) {
|
errno = map_errno(WSAGetLastError());
|
||||||
int i;
|
r = -1;
|
||||||
|
|
||||||
for (i = 0; i < fileset->fd_count; i++) {
|
|
||||||
if (fileset->fd_array[i] == fd) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == fileset->fd_count) {
|
|
||||||
if (fileset->fd_count < FD_SETSIZE) {
|
|
||||||
fileset->fd_array[i] = fd;
|
|
||||||
fileset->fd_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ReadConsoleInput((HANDLE)fd, &ir, 1, &n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileset->fd_count;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PIPE_PEEK_INTERVAL (10 * 1000) /* usec */
|
|
||||||
|
|
||||||
long
|
long
|
||||||
rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
||||||
struct timeval *timeout)
|
struct timeval *timeout)
|
||||||
{
|
{
|
||||||
long r;
|
long r;
|
||||||
fd_set file_rd;
|
|
||||||
fd_set file_wr;
|
|
||||||
fd_set pipe_rd;
|
fd_set pipe_rd;
|
||||||
fd_set cons_rd;
|
fd_set unknown_rd;
|
||||||
|
fd_set unknown_wr;
|
||||||
#ifdef USE_INTERRUPT_WINSOCK
|
#ifdef USE_INTERRUPT_WINSOCK
|
||||||
fd_set trap;
|
fd_set trap;
|
||||||
#endif /* USE_INTERRUPT_WINSOCK */
|
#endif /* USE_INTERRUPT_WINSOCK */
|
||||||
int file_nfds;
|
|
||||||
int pipe_nfds;
|
|
||||||
int cons_nfds;
|
|
||||||
struct timeval remainder;
|
|
||||||
struct timeval wait;
|
|
||||||
|
|
||||||
|
if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (!NtSocketsInitialized) {
|
if (!NtSocketsInitialized) {
|
||||||
StartSockets();
|
StartSockets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pipe_rd.fd_count = 0;
|
||||||
|
unknown_rd.fd_count = 0;
|
||||||
|
unknown_wr.fd_count = 0;
|
||||||
|
|
||||||
|
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! */
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
if (rd && rd->fd_count > r) r = rd->fd_count;
|
if (rd && rd->fd_count > r) r = rd->fd_count;
|
||||||
if (wr && wr->fd_count > r) r = wr->fd_count;
|
if (wr && wr->fd_count > r) r = wr->fd_count;
|
||||||
if (ex && ex->fd_count > r) r = ex->fd_count;
|
if (ex && ex->fd_count > r) r = ex->fd_count;
|
||||||
if (nfds > r) nfds = r;
|
if (nfds > r) nfds = r;
|
||||||
if (nfds == 0 && timeout) {
|
|
||||||
Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pipe_nfds = extract_pipe_fd(rd, &pipe_rd);
|
|
||||||
cons_nfds = extract_console_fd(rd, &cons_rd);
|
|
||||||
nfds -= pipe_nfds;
|
|
||||||
file_nfds = collect_file_fd(rd, &file_rd);
|
|
||||||
file_nfds += collect_file_fd(wr, &file_wr);
|
|
||||||
if (file_nfds) {
|
|
||||||
// assume normal files are always readable/writable,
|
|
||||||
// and pipes are always writable.
|
|
||||||
// fake read/write fd_set and return value
|
|
||||||
if (rd) *rd = file_rd;
|
|
||||||
if (wr) *wr = file_wr;
|
|
||||||
return file_nfds;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if USE_INTERRUPT_WINSOCK
|
#if USE_INTERRUPT_WINSOCK
|
||||||
if (ex)
|
if (ex)
|
||||||
|
@ -2138,60 +2042,34 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
|
||||||
ex = &trap;
|
ex = &trap;
|
||||||
#endif /* USE_INTERRUPT_WINSOCK */
|
#endif /* USE_INTERRUPT_WINSOCK */
|
||||||
|
|
||||||
if (timeout)
|
RUBY_CRITICAL(
|
||||||
remainder = *timeout;
|
if (pipe_rd.fd_count) {
|
||||||
wait.tv_sec = 0;
|
long sec = timeout ? timeout->tv_sec + 1 : 0/*dummy*/;
|
||||||
RUBY_CRITICAL(do{
|
while (!timeout || sec--) {
|
||||||
if (pipe_nfds) {
|
fd_set buf; buf.fd_count = 0;
|
||||||
r = peek_pipe(&pipe_rd, &file_rd);
|
// pipe
|
||||||
if (r > 0) {
|
extract_fd(&buf, &pipe_rd, is_readable_pipe);
|
||||||
if (rd) *rd = file_rd;
|
// socket
|
||||||
if (wr) wr->fd_count = 0;
|
if (buf.fd_count) {
|
||||||
break;
|
struct timeval val; val.tv_sec = 0; val.tv_usec = 0;
|
||||||
}
|
r = do_select(nfds, rd, wr, ex, &val);
|
||||||
|
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 only readable pipe?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct timeval val; val.tv_sec = 1; val.tv_usec = 0;
|
||||||
|
r = do_select(nfds, rd, wr, ex, &val);
|
||||||
|
if (r) break; // readable or error (not pending)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (cons_nfds) {
|
else
|
||||||
r = peek_console(&cons_rd, &file_rd);
|
r = do_select(nfds, rd, wr, ex, timeout);
|
||||||
if (r > 0) {
|
);
|
||||||
if (rd) *rd = file_rd;
|
|
||||||
if (wr) wr->fd_count = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (timeout && remainder.tv_sec == 0 &&
|
|
||||||
remainder.tv_usec < PIPE_PEEK_INTERVAL) {
|
|
||||||
wait.tv_usec = remainder.tv_usec;
|
|
||||||
remainder.tv_usec = 0;
|
|
||||||
}
|
|
||||||
else if (timeout && remainder.tv_usec < PIPE_PEEK_INTERVAL) {
|
|
||||||
remainder.tv_sec--;
|
|
||||||
remainder.tv_usec += 1000 * 1000 * 1000L- PIPE_PEEK_INTERVAL;
|
|
||||||
wait.tv_usec = PIPE_PEEK_INTERVAL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (timeout)
|
|
||||||
remainder.tv_usec -= PIPE_PEEK_INTERVAL;
|
|
||||||
wait.tv_usec = PIPE_PEEK_INTERVAL;
|
|
||||||
}
|
|
||||||
if (nfds == 0) {
|
|
||||||
Sleep(wait.tv_sec * 1000 + wait.tv_usec / 1000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
r = select(nfds, rd, wr, ex, &wait);
|
|
||||||
if (r == SOCKET_ERROR) {
|
|
||||||
errno = map_errno(WSAGetLastError());
|
|
||||||
r = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (r > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (timeout &&
|
|
||||||
remainder.tv_sec == 0 && remainder.tv_usec == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (0));
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue