[ Bjarni R. Einarsson / blog: IS EN ]


Perl IO::Select infinite loop bug, work-around and fix.

2010-05-16 09:47

I just sent an e-mail to the perl5-porters mailing list, describing a bug in and a potential fix for the IO::Select module.

Googling it, this bug has been reported at least once before (in 2005), but no fix was proposed and it seems no-one could be bothered to track it down. The bug is probably 12 years old by now. Crazy. I will be pretty happy if my solution is accepted.

Update: Resubmitted via perlbug, issue number 75156.

...

For the nerds in the audience, here is the story:

IO::Select is Perl's standard OO wrapper around the POSIX select() call. It is in my opinion an example of a good OO abstraction, hiding away the arcana of constructing select() bitmaps and interpreting their results behind a nice simple API.

However, every time I have used it, my IO::Select based servers have been prone to going into infinite CPU-sucking loops - every now and then, IO::Select would simply stop working.

This is trivially triggered by closing a file-handle which IO::Select is still watching.

I found I could avoid the problem (for the most part) by taking care to always remove file-handles from my IO::Select objects before closing them, but this was only a partial solution as either the OS or lower-level APIs could (and would) still close file-handles without 'asking me' first, on certain conditions.

I could trigger exactly that in an IO::Select based HTTP proxy I was working on this weekend, simply by hitting ESC at the right moment in my web-browser. Not exactly an edge case!

This problem can be detected with careful error handling around the IO::Select call, but it turns out that even when the problem has been detected, there is no way to remove the trouble-making file-handle from IO::Select. The only option left is to discard the IO::Select object entirely and build a new one, which I consider a relatively ugly workaround.

This is in my opinion a bug, and last Friday, on a rainy night in a guest-house in Kazimierz Dolny, I decided to see if I could fix it. I think I succeeded, but we'll see what the perl5-porters think.

The problem I found in the IO::Select module was that all the code to do with adding or removing file-handles depended on the result of a fileno() call - but fileno() returns undef once a file-handle has been closed. So, in the case of fileno() being undef, I simply added a linear search for the object in question. It seems to work.

Of course, my code still has the ugly work-around I described above (and probably always will), because it will take a while for my change to get reviewed, approved, integrated and then distributed to every single Linux machine on the planet... oh wait, that will probably never happen.

The workaround, for posterity, looks something like this:

my $newSel = IO::Select->new();
foreach my $handle ($oldSel->handles()) {
    $newSel->add($handle) if (defined $handle->fileno());
}
$oldSel = $newSel;

I hope my little bug-fix will make some future Perl programmers' life a little bit easier. And in the meantime, I hope people Googling for help will find this blog-post.

Comments are closed.

Nýtt í dagbókinni