Skip to content

Commit 4614918

Browse files
committed
merge revision(s) 16379:
* win32/win32.c (rb_w32_select): backport from trunk. [ruby-talk:300743] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_5@17288 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 81ac0c5 commit 4614918

File tree

3 files changed

+227
-56
lines changed

3 files changed

+227
-56
lines changed

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
Sun Jun 15 22:49:12 2008 NAKAMURA Usaku <usa@ruby-lang.org>
2+
3+
* win32/win32.c (rb_w32_select): backport from trunk.
4+
[ruby-talk:300743]
5+
16
Sun Jun 15 22:47:37 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
27

38
* lib/delegate.rb (SimpleDelegator::dup): removed needless argument.

version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#define RUBY_RELEASE_DATE "2008-06-15"
33
#define RUBY_VERSION_CODE 185
44
#define RUBY_RELEASE_CODE 20080615
5-
#define RUBY_PATCHLEVEL 205
5+
#define RUBY_PATCHLEVEL 206
66

77
#define RUBY_VERSION_MAJOR 1
88
#define RUBY_VERSION_MINOR 8

win32/win32.c

Lines changed: 221 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ static void invalid_parameter(const wchar_t *expr, const wchar_t *func, const wc
371371
}
372372
#endif
373373

374+
static CRITICAL_SECTION select_mutex;
374375
static BOOL fWinsock;
375376
static char *envarea;
376377
static void
@@ -384,6 +385,7 @@ exit_handler(void)
384385
FreeEnvironmentStrings(envarea);
385386
envarea = NULL;
386387
}
388+
DeleteCriticalSection(&select_mutex);
387389
}
388390

389391
static void
@@ -472,6 +474,8 @@ NtInitialize(int *argc, char ***argv)
472474

473475
init_stdhandle();
474476

477+
InitializeCriticalSection(&select_mutex);
478+
475479
atexit(exit_handler);
476480

477481
// Initialize Winsock
@@ -2043,87 +2047,250 @@ rb_w32_fdisset(int fd, fd_set *set)
20432047
static int NtSocketsInitialized = 0;
20442048

20452049
static int
2046-
extract_file_fd(fd_set *set, fd_set *fileset)
2050+
extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
20472051
{
2048-
int idx;
2052+
int s = 0;
2053+
if (!src || !dst) return 0;
20492054

2050-
fileset->fd_count = 0;
2051-
if (!set)
2052-
return 0;
2053-
for (idx = 0; idx < set->fd_count; idx++) {
2054-
SOCKET fd = set->fd_array[idx];
2055+
while (s < src->fd_count) {
2056+
SOCKET fd = src->fd_array[s];
20552057

2056-
if (!is_socket(fd)) {
2057-
int i;
2058+
if (!func || (*func)(fd)) { /* move it to dst */
2059+
int d;
20582060

2059-
for (i = 0; i < fileset->fd_count; i++) {
2060-
if (fileset->fd_array[i] == fd) {
2061-
break;
2062-
}
2061+
for (d = 0; d < dst->fd_count; d++) {
2062+
if (dst->fd_array[d] == fd) break;
20632063
}
2064-
if (i == fileset->fd_count) {
2065-
if (fileset->fd_count < FD_SETSIZE) {
2066-
fileset->fd_array[i] = fd;
2067-
fileset->fd_count++;
2068-
}
2064+
if (d == dst->fd_count && dst->fd_count < FD_SETSIZE) {
2065+
dst->fd_array[dst->fd_count++] = fd;
2066+
}
2067+
memmove(
2068+
&src->fd_array[s],
2069+
&src->fd_array[s+1],
2070+
sizeof(src->fd_array[0]) * (--src->fd_count - s));
2071+
}
2072+
else s++;
2073+
}
2074+
2075+
return dst->fd_count;
2076+
}
2077+
2078+
static int
2079+
is_not_socket(SOCKET sock)
2080+
{
2081+
return !is_socket(sock);
2082+
}
2083+
2084+
static int
2085+
is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */
2086+
{
2087+
int ret;
2088+
2089+
RUBY_CRITICAL(
2090+
ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE)
2091+
);
2092+
2093+
return ret;
2094+
}
2095+
2096+
static int
2097+
is_readable_pipe(SOCKET sock) /* call this for pipe only */
2098+
{
2099+
int ret;
2100+
DWORD n = 0;
2101+
2102+
RUBY_CRITICAL(
2103+
if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
2104+
ret = (n > 0);
2105+
}
2106+
else {
2107+
ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */
2108+
}
2109+
);
2110+
2111+
return ret;
2112+
}
2113+
2114+
static int
2115+
is_console(SOCKET sock) /* DONT call this for SOCKET! */
2116+
{
2117+
int ret;
2118+
DWORD n = 0;
2119+
INPUT_RECORD ir;
2120+
2121+
RUBY_CRITICAL(
2122+
ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n))
2123+
);
2124+
2125+
return ret;
2126+
}
2127+
2128+
static int
2129+
is_readable_console(SOCKET sock) /* call this for console only */
2130+
{
2131+
int ret = 0;
2132+
DWORD n = 0;
2133+
INPUT_RECORD ir;
2134+
2135+
RUBY_CRITICAL(
2136+
if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
2137+
if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
2138+
ir.Event.KeyEvent.uChar.AsciiChar) {
2139+
ret = 1;
2140+
}
2141+
else {
2142+
ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
2143+
}
2144+
}
2145+
);
2146+
2147+
return ret;
2148+
}
2149+
2150+
static int
2151+
do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
2152+
struct timeval *timeout)
2153+
{
2154+
int r = 0;
2155+
2156+
if (nfds == 0) {
2157+
if (timeout)
2158+
rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
2159+
else
2160+
rb_w32_sleep(INFINITE);
2161+
}
2162+
else {
2163+
RUBY_CRITICAL(
2164+
EnterCriticalSection(&select_mutex);
2165+
r = select(nfds, rd, wr, ex, timeout);
2166+
LeaveCriticalSection(&select_mutex);
2167+
if (r == SOCKET_ERROR) {
2168+
errno = map_errno(WSAGetLastError());
2169+
r = -1;
20692170
}
2171+
);
2172+
}
2173+
2174+
return r;
2175+
}
2176+
2177+
static inline int
2178+
subst(struct timeval *rest, const struct timeval *wait)
2179+
{
2180+
while (rest->tv_usec < wait->tv_usec) {
2181+
if (rest->tv_sec <= wait->tv_sec) {
2182+
return 0;
20702183
}
2184+
rest->tv_sec -= 1;
2185+
rest->tv_usec += 1000 * 1000;
20712186
}
2072-
return fileset->fd_count;
2187+
rest->tv_sec -= wait->tv_sec;
2188+
rest->tv_usec -= wait->tv_usec;
2189+
return 1;
20732190
}
20742191

2192+
static inline int
2193+
compare(const struct timeval *t1, const struct timeval *t2)
2194+
{
2195+
if (t1->tv_sec < t2->tv_sec)
2196+
return -1;
2197+
if (t1->tv_sec > t2->tv_sec)
2198+
return 1;
2199+
if (t1->tv_usec < t2->tv_usec)
2200+
return -1;
2201+
if (t1->tv_usec > t2->tv_usec)
2202+
return 1;
2203+
return 0;
2204+
}
2205+
2206+
#undef Sleep
20752207
long
20762208
rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
20772209
struct timeval *timeout)
20782210
{
20792211
long r;
2080-
fd_set file_rd;
2081-
fd_set file_wr;
2082-
#ifdef USE_INTERRUPT_WINSOCK
2083-
fd_set trap;
2084-
#endif /* USE_INTERRUPT_WINSOCK */
2085-
int file_nfds;
2212+
fd_set pipe_rd;
2213+
fd_set cons_rd;
2214+
fd_set else_rd;
2215+
fd_set else_wr;
2216+
int nonsock = 0;
20862217

2218+
if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
2219+
errno = EINVAL;
2220+
return -1;
2221+
}
20872222
if (!NtSocketsInitialized) {
20882223
StartSockets();
20892224
}
2225+
2226+
// assume else_{rd,wr} (other than socket, pipe reader, console reader)
2227+
// are always readable/writable. but this implementation still has
2228+
// problem. if pipe's buffer is full, writing to pipe will block
2229+
// until some data is read from pipe. but ruby is single threaded system,
2230+
// so whole system will be blocked forever.
2231+
2232+
else_rd.fd_count = 0;
2233+
nonsock += extract_fd(&else_rd, rd, is_not_socket);
2234+
2235+
pipe_rd.fd_count = 0;
2236+
extract_fd(&pipe_rd, &else_rd, is_pipe); // should not call is_pipe for socket
2237+
2238+
cons_rd.fd_count = 0;
2239+
extract_fd(&cons_rd, &else_rd, is_console); // ditto
2240+
2241+
else_wr.fd_count = 0;
2242+
nonsock += extract_fd(&else_wr, wr, is_not_socket);
2243+
20902244
r = 0;
20912245
if (rd && rd->fd_count > r) r = rd->fd_count;
20922246
if (wr && wr->fd_count > r) r = wr->fd_count;
20932247
if (ex && ex->fd_count > r) r = ex->fd_count;
20942248
if (nfds > r) nfds = r;
2095-
if (nfds == 0 && timeout) {
2096-
Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
2097-
return 0;
2098-
}
2099-
file_nfds = extract_file_fd(rd, &file_rd);
2100-
file_nfds += extract_file_fd(wr, &file_wr);
2101-
if (file_nfds)
2249+
21022250
{
2103-
// assume normal files are always readable/writable
2104-
// fake read/write fd_set and return value
2105-
if (rd) *rd = file_rd;
2106-
if (wr) *wr = file_wr;
2107-
return file_nfds;
2108-
}
2251+
struct timeval rest;
2252+
struct timeval wait;
2253+
struct timeval zero;
2254+
if (timeout) rest = *timeout;
2255+
wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms
2256+
zero.tv_sec = 0; zero.tv_usec = 0; // 0ms
2257+
do {
2258+
if (nonsock) {
2259+
// modifying {else,pipe,cons}_rd is safe because
2260+
// if they are modified, function returns immediately.
2261+
extract_fd(&else_rd, &pipe_rd, is_readable_pipe);
2262+
extract_fd(&else_rd, &cons_rd, is_readable_console);
2263+
}
21092264

2110-
#if USE_INTERRUPT_WINSOCK
2111-
if (ex)
2112-
trap = *ex;
2113-
else
2114-
trap.fd_count = 0;
2115-
if (trap.fd_count < FD_SETSIZE)
2116-
trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
2117-
// else unable to catch interrupt.
2118-
ex = &trap;
2119-
#endif /* USE_INTERRUPT_WINSOCK */
2265+
if (else_rd.fd_count || else_wr.fd_count) {
2266+
r = do_select(nfds, rd, wr, ex, &zero); // polling
2267+
if (r < 0) break; // XXX: should I ignore error and return signaled handles?
2268+
r += extract_fd(rd, &else_rd, NULL); // move all
2269+
r += extract_fd(wr, &else_wr, NULL); // move all
2270+
break;
2271+
}
2272+
else {
2273+
struct timeval *dowait =
2274+
compare(&rest, &wait) < 0 ? &rest : &wait;
2275+
2276+
fd_set orig_rd;
2277+
fd_set orig_wr;
2278+
fd_set orig_ex;
2279+
if (rd) orig_rd = *rd;
2280+
if (wr) orig_wr = *wr;
2281+
if (ex) orig_ex = *ex;
2282+
r = do_select(nfds, rd, wr, ex, &zero); // polling
2283+
if (r != 0) break; // signaled or error
2284+
if (rd) *rd = orig_rd;
2285+
if (wr) *wr = orig_wr;
2286+
if (ex) *ex = orig_ex;
2287+
2288+
// XXX: should check the time select spent
2289+
Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
2290+
}
2291+
} while (!timeout || subst(&rest, &wait));
2292+
}
21202293

2121-
RUBY_CRITICAL({
2122-
r = select(nfds, rd, wr, ex, timeout);
2123-
if (r == SOCKET_ERROR) {
2124-
errno = map_errno(WSAGetLastError());
2125-
}
2126-
});
21272294
return r;
21282295
}
21292296

@@ -3258,7 +3425,6 @@ rb_w32_times(struct tms *tmbuf)
32583425
return 0;
32593426
}
32603427

3261-
#undef Sleep
32623428
#define yield_once() Sleep(0)
32633429
#define yield_until(condition) do yield_once(); while (!(condition))
32643430

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy