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

**URL:** <https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051>\
**Category:** Ruby\
**Created:** [March 27, 2008, 6:45am UTC](https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051 "2008-03-27T06:45:30Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![maz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e9c0ed/32.png) [@maz](https://www.ruby-forum.com/u/maz)\
**Post date:** [March 27, 2008, 6:45am UTC](https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051/1 "2008-03-27T06:45:30Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![maz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e9c0ed/32.png) [@maz](https://www.ruby-forum.com/u/maz)\
**Post date:** [March 27, 2008, 7:25am UTC](https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051/2 "2008-03-27T07:25:56Z")

</div>

On Mar 27, 2:41 am, “Just Another Victim of the Ambient M.”  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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](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,

---

<div class="post-metadata">

**Author:** ![maz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e9c0ed/32.png) [@maz](https://www.ruby-forum.com/u/maz)\
**Post date:** [March 27, 2008, 10:39am UTC](https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051/3 "2008-03-27T10:39:07Z")

</div>

Hi,

Luis L. wrote:

> On Mar 27, 2:41 am, “Just Another Victim of the … Morality”  
> [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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:
> 
> [Parked at Loopia](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.

---

<div class="post-metadata">

**Author:** ![maz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e9c0ed/32.png) [@maz](https://www.ruby-forum.com/u/maz)\
**Post date:** [March 27, 2008, 11:07am UTC](https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051/4 "2008-03-27T11:07:24Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![maz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e9c0ed/32.png) [@maz](https://www.ruby-forum.com/u/maz)\
**Post date:** [March 27, 2008, 2:40pm UTC](https://www.ruby-forum.com/t/is-this-a-threading-bug-in-ruby-185-21-on-win32/133051/5 "2008-03-27T14:40:45Z")

</div>

On Mar 27, 6:38 am, Heesob P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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 🙂

Regards and thank you again,
