From: Jan Dubois Date: Tue, 13 Oct 2009 23:46:58 +0000 (-0700) Subject: The winsock select() implementation doesn't support all empty 'fd_set's. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=e4d771f5006ebd70b76422437cce60e9ac40c830;p=p5sagit%2Fp5-mst-13.2.git The winsock select() implementation doesn't support all empty 'fd_set's. The code already contained a workaround for the special case select(undef, undef, undef, $sleep); but didn't handle the case when actual bit vectors were passed in that didn't have any bits set. Fixes http://rt.perl.org/rt3/Public/Bug/Display.html?id=54544 --- diff --git a/t/op/sselect.t b/t/op/sselect.t index 0f877b1..332b7c0 100644 --- a/t/op/sselect.t +++ b/t/op/sselect.t @@ -7,7 +7,7 @@ BEGIN { require 'test.pl'; -plan (9); +plan (11); my $blank = ""; eval {select undef, $blank, $blank, 0}; @@ -30,3 +30,14 @@ eval {select $blank, "a", $blank, 0}; like ($@, qr/^Modification of a read-only value attempted/); eval {select $blank, $blank, "a", 0}; like ($@, qr/^Modification of a read-only value attempted/); + +my $sleep = 3; +my $t = time; +select(undef, undef, undef, $sleep); +ok(time-$t >= $sleep, "$sleep seconds have passed"); + +my $empty = ""; +vec($empty,0,1) = 0; +$t = time; +select($empty, undef, undef, $sleep); +ok(time-$t >= $sleep, "$sleep seconds have passed"); diff --git a/win32/win32sck.c b/win32/win32sck.c index 8ff0196..dd46bb3 100644 --- a/win32/win32sck.c +++ b/win32/win32sck.c @@ -261,18 +261,8 @@ win32_select(int nfds, Perl_fd_set* rd, Perl_fd_set* wr, Perl_fd_set* ex, const #ifdef USE_SOCKETS_AS_HANDLES int i, fd, save_errno = errno; FD_SET nrd, nwr, nex; + bool just_sleep = TRUE; - /* winsock seems incapable of dealing with all three null fd_sets, - * so do the (millisecond) sleep as a special case - */ - if (!(rd || wr || ex)) { - if (timeout) - Sleep(timeout->tv_sec * 1000 + - timeout->tv_usec / 1000); /* do the best we can */ - else - Sleep(UINT_MAX); - return 0; - } StartSockets(); FD_ZERO(&nrd); @@ -282,17 +272,32 @@ win32_select(int nfds, Perl_fd_set* rd, Perl_fd_set* wr, Perl_fd_set* ex, const if (rd && PERL_FD_ISSET(i,rd)) { fd = TO_SOCKET(i); FD_SET((unsigned)fd, &nrd); + just_sleep = FALSE; } if (wr && PERL_FD_ISSET(i,wr)) { fd = TO_SOCKET(i); FD_SET((unsigned)fd, &nwr); + just_sleep = FALSE; } if (ex && PERL_FD_ISSET(i,ex)) { fd = TO_SOCKET(i); FD_SET((unsigned)fd, &nex); + just_sleep = FALSE; } } + /* winsock seems incapable of dealing with all three fd_sets being empty, + * so do the (millisecond) sleep as a special case + */ + if (just_sleep) { + if (timeout) + Sleep(timeout->tv_sec * 1000 + + timeout->tv_usec / 1000); /* do the best we can */ + else + Sleep(UINT_MAX); + return 0; + } + errno = save_errno; SOCKET_TEST_ERROR(r = select(nfds, &nrd, &nwr, &nex, timeout)); save_errno = errno;