Hi,
Luis said:
I've asked about this back in September 2007 at ruby-core mailing
list, no answer. I'm copying my post with details more information:
Hello Ruby Developers.
I've been trying to determine what is wrong with this simple script:
http://pastie.caboo.se/101434
t = Thread.new {
while true
puts "printing a line"
sleep 2
end
}
gets
t.exit
puts "exiting"
===
And found that all the IO (stdin) is broken on Windows:
custom build with MinGW (3.4.5 -- mingw special)
custom build with VC8
official build VC6
All behave the same way: just 1 line of "printing a line" gets
actually printed, and the world halt until you hit enter.
I saw a few post dating 2003 about this... and this brakes the
cross-platform nature of most of ruby: works on some platform, don't
work on other.
Since 1.8.6 will stay with us a bit longer, any ideas how to solve it?
Park Heesob posted a patch back then, but it don't work as expected
(this problem didn't get solved).
For the record: 1.9.0 don't show this issue, but YARV is another
different breed.
Thanks in advance for your time.
==
Even it doesn't solve your issue, explain it better.
Still, no answer, no solution :'(
Regards,
Here is the patched code of rb_win_selected function
(win32.c,ruby-1.8.6-p111)
It will fix Thread blocking problem with standard input waiting.
long
rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
struct timeval *timeout)
{
DWORD ms_total, limit;
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS];
int n_handles = 0, i;
fd_set aread, awrite, aexcept;
int retcode;
long r;
fd_set file_rd;
fd_set file_wr;
#ifdef USE_INTERRUPT_WINSOCK
fd_set trap;
#endif /* USE_INTERRUPT_WINSOCK */
int file_nfds;
#define SAFE_FD_ISSET(fd, set) (set != NULL && rb_w32_fdisset(fd, set))
/* calculate how long we need to wait in milliseconds */
if (timeout == NULL) {
ms_total = INFINITE;
} else {
ms_total = timeout->tv_sec * 1000;
ms_total += timeout->tv_usec / 1000;
}
/* build an array of handles for non-sockets */
for (i = 0; i <= nfds; i++) {
if (SAFE_FD_ISSET(i, rd) || SAFE_FD_ISSET(i, wr)) {
handles[n_handles] = (HANDLE)TO_SOCKET(i);
if ((SOCKET)handles[n_handles]==TO_SOCKET(0)) { /* only treat stdin
*/
handle_slot_to_fd[n_handles] = i;
n_handles++;
}
}
}
if (!NtSocketsInitialized) {
StartSockets();
}
r = 0;
if (rd && rd->fd_count > r) r = rd->fd_count;
if (wr && wr->fd_count > r) r = wr->fd_count;
if (ex && ex->fd_count > r) r = ex->fd_count;
if (nfds > r) nfds = r;
if (nfds == 0 && timeout) {
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)
{
if(n_handles>0) {
FD_ZERO(&aread);
FD_ZERO(&awrite);
limit = GetTickCount() + ms_total;
do {
DWORD wret;
retcode = 0;
wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE,
retcode > 0 ? 0 : 100, QS_ALLEVENTS);
if (wret == WAIT_TIMEOUT) {
/* set retcode to 0; this is the default.
* select() may have set it to something else,
* in which case we leave it alone, so this branch
* does nothing */
;
} else if (wret == WAIT_FAILED) {
if (retcode == 0) {
retcode = -1;
}
} else {
if (retcode < 0) {
retcode = 0;
}
for (i = 0; i < n_handles; i++) {
if (WAIT_OBJECT_0 == WaitForSingleObject(handles
, 0)) {
if (SAFE_FD_ISSET(handle_slot_to_fd, rd)) {
rb_w32_fdset(handle_slot_to_fd, &aread);
}
if (SAFE_FD_ISSET(handle_slot_to_fd, wr)) {
rb_w32_fdset(handle_slot_to_fd, &awrite);
}
retcode++;
}
}
}
} while (retcode == 0 &&
(ms_total == INFINITE || GetTickCount() < limit));
if (rd) *rd = aread;
if (wr) *wr = awrite;
}
else {
// assume normal files are always readable/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 (ex)
trap = *ex;
else
trap.fd_count = 0;
if (trap.fd_count < FD_SETSIZE)
trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
// else unable to catch interrupt.
ex = &trap;
#endif /* USE_INTERRUPT_WINSOCK */
RUBY_CRITICAL({
r = select(nfds, rd, wr, ex, timeout);
if (r == SOCKET_ERROR) {
errno = map_errno(WSAGetLastError());
}
});
return r;
}
Regards,
Park Heesob