[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

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

Randy R

3/27/2008 5:42:00 AM

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



4 Answers

Luis Lavena

3/27/2008 6:22:00 AM

0

On Mar 27, 2:41 am, "Just Another Victim of the Ambient Morality"
<ihates...@hotmail.com> wrote:
> 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

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

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,
--
Luis Lavena

Heesob Park

3/27/2008 9:39:00 AM

0

Hi,

Luis Lavena wrote:
> On Mar 27, 2:41 am, "Just Another Victim of the .. Morality"
> <ihates...@hotmail.com> 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...
>
> 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[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 Heesob
--
Posted via http://www.ruby-....

James Tucker

3/27/2008 10:04:00 AM

0


On 27 Mar 2008, at 09:38, Heesob Park wrote:
> Hi,
>
> Luis Lavena wrote:
>> On Mar 27, 2:41 am, "Just Another Victim of the .. Morality"
>> <ihates...@hotmail.com> 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...
>>
>> 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.

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

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

>>
>>
>> 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

Are there any known problems with this patch?

Luis Lavena

3/27/2008 1:38:00 PM

0

On Mar 27, 6:38 am, Heesob Park <pha...@gmail.com> 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,
--
Luis Lavena