Is this a threading bug in Ruby-185-21 on Win32?

I’m trying to write a program that will poll some website and that is
easily terminable. I have a similar Ruby program on a Linux machine
that
polls my inbox to see if I have mail and, whenever I have new mail,
prints
the \b character. This is done by putting the polling code in a loop in
a
thread block while the main thread simply waits in a gets method. This
allows someone to exit the program simply by typing anything. However,
when
I try this on Win32, it appears that the Ruby interpreter blocks in the
gets
call and the other thread never gets any execution time.
So, there appears to be a great discrepancy between the
implementations
on the two systems. Is this really the case? Why is this? Is this
necessarily so or can we change this? Shouldn’t we like to change this?
What do you all think?
What follows is some example code. On my Win32 system, this program
only counts up to 102.
Thank you for looking over this…

puts ‘start’
Thread.new do
count = 0
loop do
puts count
count += 1
end
end
gets

On Mar 27, 2:41 am, “Just Another Victim of the Ambient M.”
[email protected] wrote:

necessarily so or can we change this? Shouldn’t we like to change this?
count += 1
end
end
gets

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 H. 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,

Hi,

Luis L. wrote:

On Mar 27, 2:41 am, “Just Another Victim of the … Morality”
[email protected] wrote:

necessarily so or can we change this? Shouldn’t we like to change this?
count += 1
end
end
gets

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 H. 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[i], 0)) {

    if (SAFE_FD_ISSET(handle_slot_to_fd[i], rd)) {
     rb_w32_fdset(handle_slot_to_fd[i], &aread);
    }
    if (SAFE_FD_ISSET(handle_slot_to_fd[i], wr)) {
     rb_w32_fdset(handle_slot_to_fd[i], &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 H.

On 27 Mar 2008, at 09:38, Heesob P. wrote:

gets
t = Thread.new {
===

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.

Yup, complete hard block on read()

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?

HighLine and EventMachine have both proven possible for me. I hacked
together a mini-irb tool which is then more useful for stab testing
something like GServer in irb. Mind you, after loading up
eventmachines reactor for the keyboard, using GServer seems a little
silly =)

Park H. 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.

Right, the blocking call is probably still there, however I’ve made no
attempt to verify.

Regards,

Here is the patched code of rb_win_selected function

Are there any known problems with this patch?

On Mar 27, 6:38 am, Heesob P. [email protected] wrote:

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.

Thank you Park, I’ll test this later also with MinGW build

Did you know why still didn’t get merged?

I was about to scream about it at ruby-core, but after the post on
rubyinside, I don’t want to annoy more people :slight_smile:

Regards and thank you again,

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs