aboutsummaryrefslogtreecommitdiffstats
path: root/win32
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-09-14 14:30:37 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-09-14 14:30:37 +0000
commite2472dafa07c491954c3e81ee9643ade1252ce00 (patch)
tree80f6f1905f37f3b69686b4a9bc2352793bb991d9 /win32
parent9d2b69a27306058af38a7e5c1b57dd419a57fd05 (diff)
downloadruby-e2472dafa07c491954c3e81ee9643ade1252ce00.tar.gz
* win32/win32.c (collect_file_fd): rename from extract_file_fd.
* win32/win32.c (extract_pipe_fd, peek_pipe): new functions. * win32/win32.c (rb_w32_select): check pipes by polling them. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9159 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'win32')
-rw-r--r--win32/win32.c138
-rw-r--r--win32/win32.h1
2 files changed, 128 insertions, 11 deletions
diff --git a/win32/win32.c b/win32/win32.c
index e1468a1d8f..fb0875588f 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -1910,7 +1910,7 @@ rb_w32_fdisset(int fd, fd_set *set)
static int NtSocketsInitialized = 0;
static int
-extract_file_fd(fd_set *set, fd_set *fileset)
+collect_file_fd(fd_set *set, fd_set *fileset)
{
int idx;
@@ -1939,6 +1939,76 @@ extract_file_fd(fd_set *set, fd_set *fileset)
return fileset->fd_count;
}
+static int
+extract_pipe_fd(fd_set *set, fd_set *fileset)
+{
+ int idx;
+
+ 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
+peek_pipe(fd_set *set, fd_set *fileset)
+{
+ int idx;
+
+ fileset->fd_count = 0;
+ for (idx = 0; idx < set->fd_count; idx++) {
+ 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++) {
+ 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;
+}
+
+#define PIPE_PEEK_INTERVAL (10 * 1000) /* usec */
+
long
rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
struct timeval *timeout)
@@ -1946,10 +2016,14 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
long r;
fd_set file_rd;
fd_set file_wr;
+ fd_set pipe_rd;
#ifdef USE_INTERRUPT_WINSOCK
fd_set trap;
#endif /* USE_INTERRUPT_WINSOCK */
int file_nfds;
+ int pipe_nfds;
+ struct timeval remainder;
+ struct timeval wait;
if (!NtSocketsInitialized) {
StartSockets();
@@ -1963,11 +2037,13 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
return 0;
}
- file_nfds = extract_file_fd(rd, &file_rd);
- file_nfds += extract_file_fd(wr, &file_wr);
- if (file_nfds)
- {
- // assume normal files are always readable/writable
+ pipe_nfds = extract_pipe_fd(rd, &pipe_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;
@@ -1985,12 +2061,52 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
ex = &trap;
#endif /* USE_INTERRUPT_WINSOCK */
- RUBY_CRITICAL({
- r = select(nfds, rd, wr, ex, timeout);
- if (r == SOCKET_ERROR) {
- errno = map_errno(WSAGetLastError());
+ if (timeout)
+ remainder = *timeout;
+ wait.tv_sec = 0;
+ RUBY_CRITICAL(do{
+ if (pipe_nfds) {
+ r = peek_pipe(&pipe_rd, &file_rd);
+ 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;
}
diff --git a/win32/win32.h b/win32/win32.h
index bbc855e13f..d3bac885bc 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -93,6 +93,7 @@ extern "C++" {
#define strcasecmp(s1, s2) stricmp(s1, s2)
#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n)
+#define pipe(p) _pipe(p, 2048L, O_BINARY)
#define close(h) rb_w32_close(h)
#define fclose(f) rb_w32_fclose(f)
#define getpid() rb_w32_getpid()