Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.96k stars 555 forks source link

Not OK: perl v5.8.1 +MAINT19524 on MSWin32-x86-multi-thread 4.0 (UNINSTALLED) #6512

Closed p5pRT closed 16 years ago

p5pRT commented 21 years ago

Migrated from rt.perl.org#22204 (status was 'resolved')

Searchable as RT22204$

p5pRT commented 21 years ago

From @mhx

Here are my observations building perl@​19525 under Win2k using Visual C 6.0. Included are compiler warnings\, strange (unwanted?) output during 'nmake test'\, reproducible test failures in Net​::Ping and strange failures in the threads stress tests.

Compiler warnings I noticed​:

..\op.c(3232) : warning C4018​: '==' : signed/unsigned mismatch ..\op.c(198) : warning C4761​: integral size mismatch in argument; conversion supplied
..\perl.c(2321) : warning C4018​: '\<' : signed/unsigned mismatch
..\sv.c(5638) : warning C4018​: '==' : signed/unsigned mismatch
..\sv.c(5644) : warning C4018​: '\<' : signed/unsigned mismatch
Making Digest/MD5
MD5.xs(578) : warning C4101​: 'my_na' : unreferenced local variable
Making Encode
encengine.c(136) : warning C4018​: '==' : signed/unsigned mismatch
Making List/Util
Util.xs(243) : warning C4244​: '=' : conversion from 'long ' to 'unsigned char '\, possible loss of data
Util.xs(294) : warning C4244​: '=' : conversion from 'long ' to 'unsigned char '\, possible loss of data
Util.c(616) : warning C4101​: 'RETVAL' : unreferenced local variable
Making POSIX
POSIX.c(2518) : warning C4101​: 'RETVAL' : unreferenced local variable
Making SDBM_File
SDBM_File.c(278) : warning C4101​: 'key' : unreferenced local variable
SDBM_File.c(278) : warning C4700​: local variable 'key' used without having been initialized
Making Storable
Storable.xs(2382) : warning C4101​: 'ret' : unreferenced local variable
Storable.xs(4963) : warning C4101​: 'errsv' : unreferenced local variable
Making Thread
Thread.c(396) : warning C4101​: 'av' : unreferenced local variable
Thread.c(397) : warning C4101​: 'i' : unreferenced local variable
Thread.xs(472) : warning C4101​: 'sv' : unreferenced local variable
Thread.c(737) : warning C4101​: 'mg' : unreferenced local variable
Thread.c(771) : warning C4101​: 'mg' : unreferenced local variable
Thread.c(800) : warning C4101​: 'mg' : unreferenced local variable
Thread.xs(582) : warning C4101​: 'av' : unreferenced local variable
Thread.xs(581) : warning C4101​: 't' : unreferenced local variable
Thread.xs(583) : warning C4101​: 'svp' : unreferenced local variable
Making XS/Typemap
Typemap.c(802) : warning C4018​: '\<' : signed/unsigned mismatch

Strange output I noticed during the test suite run​:

../ext/IO/lib/IO/t/io_xs...............Error removing C​:\DOKUME~1\MARCUS~1\LOKALE~1\Temp\dbVHFTkgIO at ../lib/File/Temp.pm line 844\, \<_GEN_0> line 2. ../ext/IO/lib/IO/t/io_xs...............ok
../lib/Pod/t/basic.....................ok 9/11Use of uninitialized value in concatenation (.) or string at

../lib/Pod/Text/Termcap.pm line 47. | ../lib/Pod/t/basic.....................ok

Test suite failures​:

../ext/threads/t/stress_re.............dubious Test returned status 5 (wstat 1280\, 0x500)
../lib/Net/Ping/t/450_service..........NOK 8# Failed test 8 in ../lib/Net/Ping/t/450_service.t at line 77
# ../lib/Net/Ping/t/450_service.t line 77 is​: ok $p -> ping("127.0.0.1");
../lib/Net/Ping/t/450_service..........NOK 9# Failed test 9 in ../lib/Net/Ping/t/450_service.t at line 83
# ../lib/Net/Ping/t/450_service.t line 83 is​: ok $p -> ping("127.0.0.1");
../lib/Net/Ping/t/450_service..........NOK 10# Failed test 10 in ../lib/Net/Ping/t/450_service.t at line 94
# ../lib/Net/Ping/t/450_service.t line 94 is​: ok $p -> ping("127.0.0.1");
../lib/Net/Ping/t/450_service..........FAILED tests 8-10
Failed 3/26 tests\, 88.46% okay
Failed Test Stat Wstat Total Fail Failed List of Failed
-------------------------------------------------------------------------------
../ext/threads/t/stress_re.t 5 1280 ?? ?? % ??
../lib/Net/Ping/t/450_service.t 26 3 11.54% 8-10
58 tests and 664 subtests skipped.
Failed 2/786 test scripts\, 99.75% okay. 3/74916 subtests failed\, 100.00% okay.

In a second test run\, I got the following\, while 'stress_re' was ok​:

| ../ext/threads/t/stress_string.........FAILED before any test output arrived

I built a debugging version of Perl\, but unfortunately I'm not able to reproduce the threads stress test failures with it. I also couldn't reproduce the failures when running the threads tests by hand with either version.

The output of the failing ping test is as follows​:

| D​:\temp\perl\t>.\perl -I../lib ../lib/Net/Ping/t/450_service.t | 1..26 | # Running under perl version 5.008001 for MSWin32 | # Current time local​: Wed May 14 21​:24​:25 2003 | # Current time GMT​: Wed May 14 20​:24​:25 2003 | # Using Test.pm version 1.24 | ok 1 | ok 2 | ok 3 | ok 4 | ok 5 | ok 6 | ok 7 | not ok 8 | # Failed test 8 in ../lib/Net/Ping/t/450_service.t at line 77 | # ../lib/Net/Ping/t/450_service.t line 77 is​: ok $p -> ping("127.0.0.1"); | not ok 9 | # Failed test 9 in ../lib/Net/Ping/t/450_service.t at line 83 | # ../lib/Net/Ping/t/450_service.t line 83 is​: ok $p -> ping("127.0.0.1"); | not ok 10 | # Failed test 10 in ../lib/Net/Ping/t/450_service.t at line 94 | # ../lib/Net/Ping/t/450_service.t line 94 is​: ok $p -> ping("127.0.0.1"); | ok 11 | ok 12 | ok 13 | ok 14 | ok 15 | ok 16 | ok 17 | ok 18 | ok 19 | ok 20 | ok 21 | ok 22 | ok 23 | ok 24 | ok 25 | ok 26

If you need any details\, please let me know.

-- Marcus

Perl Info ``` Flags: category=install severity=none Site configuration information for perl v5.8.1: Configured by Marcus Holland at Wed May 14 21:16:57 2003. Summary of my perl5 (revision 5 version 8 subversion 1) configuration: Platform: osname=MSWin32, osvers=4.0, archname=MSWin32-x86-multi-thread uname='' config_args='undef' hint=recommended, useposix=true, d_sigaction=undef usethreads=undef use5005threads=undef useithreads=define usemultiplicity=define useperlio=define d_sfio=undef uselargefiles=define usesocks=undef use64bitint=undef use64bitall=undef uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cl', ccflags ='-nologo -Gf -W3 -MD -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_ MSVCRT_READFIX', optimize='-MD -DNDEBUG -O1', cppflags='-DWIN32' ccversion='', gccversion='', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=10 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='link', ldflags ='-nologo -nodefaultlib -release -libpath:"c:\perl\lib\CORE" -machine:x86' libpth=\lib libs= oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib perllibs= oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib libc=msvcrt.lib, so=dll, useshrplib=yes, libperl=perl58.lib gnulibc_version='undef' Dynamic Linking: dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' ' cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -release -libpath:"c:\perl\lib\CORE" -machine:x86' Locally applied patches: MAINT19524 @INC for perl v5.8.1: ..\lib D:/temp/perl/lib . Environment for perl v5.8.1: HOME (unset) LANG=DE LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=c:\bin\lcc\bin;C:\bin\doxygen\bin;C:\bin\rcs\bin;C:\bin\ImageMagick;C:\bin\gs\gs7.03\bin;C:\bin\TeX\miktex\bin;C:\bin\perl\bin\ ;C:\bin\perl-580\bin\;c:\bin;c:\bin\unix;c:\bin\vim\vim60;c:\bin\perl\bin\;C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\Prog ramme\Gemeinsame Dateien\Adaptec Shared\System;C:\Programme\MSVS\Common\Tools\WinNT;C:\Programme\MSVS\Common\MSDev98\Bin;C:\Programme\MSVS\Common\Tools;C:\Programme\ MSVS\VC98\bin PERL_BADLANG (unset) PERL_CORE=1 SHELL (unset) ```
p5pRT commented 21 years ago

From @mhx

Strange output I noticed during the test suite run​:

| ../ext/IO/lib/IO/t/io_xs...............Error removing C​:\DOKUME~1\MARCUS~1\LOKALE~1\Temp\dbVHFTkgIO at ../lib/File/Temp.pm line 844\, \<_GEN_0> line 2. | ../ext/IO/lib/IO/t/io_xs...............ok

This one is caused by File​::Temp not having the permissions to unlink the temporary file. It should not have to unlink the file at all\, as {unlink_on_close} sets the O_TEMPORARY flag\, which should do the following on Windows according to fcntl.h​:

  /* Temporary file bit - file is deleted when last handle is closed */

However\, the file won't disappear until perl exits. I really don't know why\, because O_TEMPORARY works fine when I'm using it from a C application. I got quite lost in the Perl core searching for the problem\, perhaps an I/O expert knows what's going on?

The problem can be reproduced quite easily​:

D​:\temp\perl>.\perl -Ilib -MIO​::File -e"$x=new_tmpfile IO​::File" Error removing C​:\DOKUME~1\MARCUS~1\LOKALE~1\Temp\jAe2u3ZtV5 at lib/File/Temp.pm line 844.

| ../lib/Pod/t/basic.....................ok 9/11Use of uninitialized value in concatenation (.) or string at ../lib/Pod/Text/Termcap.pm line 47. | ../lib/Pod/t/basic.....................ok

This is easier. Pod​::Text​::Termcap makes uses $ENV{HOME} without checking. This is usually not set on Windows. I think there should be some kind of check anywhere. (Does it make sense to even use Pod​::Text​::Termcap on Windows?)

Test suite failures​:

../ext/threads/t/stress_re.............dubious Test returned status 5 (wstat 1280\, 0x500)
../lib/Net/Ping/t/450_service..........NOK 8# Failed test 8 in ../lib/Net/Ping/t/450_service.t at line 77
# ../lib/Net/Ping/t/450_service.t line 77 is​: ok $p -> ping("127.0.0.1");
../lib/Net/Ping/t/450_service..........NOK 9# Failed test 9 in ../lib/Net/Ping/t/450_service.t at line 83
# ../lib/Net/Ping/t/450_service.t line 83 is​: ok $p -> ping("127.0.0.1");
../lib/Net/Ping/t/450_service..........NOK 10# Failed test 10 in ../lib/Net/Ping/t/450_service.t at line 94
# ../lib/Net/Ping/t/450_service.t line 94 is​: ok $p -> ping("127.0.0.1");
../lib/Net/Ping/t/450_service..........FAILED tests 8-10
Failed 3/26 tests\, 88.46% okay

I've tested on another Win2k machine and got the same results for Net​::Ping.

-- Marcus

p5pRT commented 21 years ago

From @mhx

| ../lib/Net/Ping/t/450_service..........NOK 8# Failed test 8 in ../lib/Net/Ping/t/450_service.t at line 77 | # ../lib/Net/Ping/t/450_service.t line 77 is​: ok $p -> ping("127.0.0.1"); | ../lib/Net/Ping/t/450_service..........NOK 9# Failed test 9 in ../lib/Net/Ping/t/450_service.t at line 83 | # ../lib/Net/Ping/t/450_service.t line 83 is​: ok $p -> ping("127.0.0.1"); | ../lib/Net/Ping/t/450_service..........NOK 10# Failed test 10 in ../lib/Net/Ping/t/450_service.t at line 94 | # ../lib/Net/Ping/t/450_service.t line 94 is​: ok $p -> ping("127.0.0.1"); | ../lib/Net/Ping/t/450_service..........FAILED tests 8-10 | Failed 3/26 tests\, 88.46% okay

I think I know why these tests failed and I also have a patch for lib/Net/Ping.pm that fixes the failures. However\, as this is my first patch to a Perl core module\, I'd appreciate it if someone would have a closer look.

One problem is that in Net​::Ping on MSWin32\, a tcp ping is run in a separate process using fork(). Even though $ret is set in the child process\, $ret is not set in the parent process. As it defaults to 0\, tcp pings are never successful. My solution was to explicitly set $ret in the parent process depending on the exit status (0 on success\, $! on failure) of the child process.

The other problem is that a process exit code must be in the range 0..255. As the child process exits with $!\, if $! is greater than 255\, the exit code will actually be ($! & 255). This does not work if connect() fails with ECONNREFUSED\, which sets $! to 10061 in the child process. The parent process will set $! based on the child's exit code\, and thus to 77. This is why the check for ECONNREFUSED fails in the parent process. My solution was to do that check in the child process instead.

Additionally\, I checked that $! \<= 255 in the child process. If this is not the case\, the child exits with code 255. This is just to make sure that 0 is not accidentially returned.

-- Marcus

p5pRT commented 21 years ago

From @mhx

Net-Ping.patch ```diff --- lib/Net/Ping.pm.org Mon Apr 21 18:22:40 2003 +++ lib/Net/Ping.pm Thu May 15 22:00:56 2003 @@ -527,7 +527,9 @@ }; my $do_connect = sub { $self->{"ip"} = $ip; - return ($ret = connect($self->{"fh"}, $saddr)); + # ECONNREFUSED is 10061 on MSWin32. If we pass it as child error through $?, + # we'll get (10061 & 255) = 77, so we cannot check it in the parent process. + return ($ret = connect($self->{"fh"}, $saddr) || ($! == ECONNREFUSED && !$self->{"econnrefused"})); }; my $do_connect_nb = sub { # Set O_NONBLOCK property on filehandle @@ -613,7 +615,8 @@ exit 0; } else { # Pass the error status to the parent - exit $!; + # Make sure that $! <= 255 + exit($! <= 255 ? $! : 255); } } @@ -638,6 +641,8 @@ # within the timeout &{ $do_connect }(); } + # $ret cannot be set by the child process + $ret = !$child_errno; } else { # Time must have run out. # Put that choking client out of its misery ```
p5pRT commented 21 years ago

From @gsar

On Thu\, 15 May 2003 22​:25​:37 +0200\, "Marcus Holland-Moritz" wrote​:

One problem is that in Net​::Ping on MSWin32\, a tcp ping is run in a separate process using fork().

I don't think this is really necessary. Non-blocking connects should work fine on Windows NT (I've checked at least Windows 2000).

Even though $ret is set in the child process\, $ret is not set in the parent process. As it defaults to 0\, tcp pings are never successful. My solution was to explicitly set $ret in the parent process depending on the exit status (0 on success\, $! on failure) of the child process.

The other problem is that a process exit code must be in the range 0..255. As the child process exits with $!\, if $! is greater than 255\, the exit code will actually be ($! & 255). This does not work if connect() fails with ECONNREFUSED\, which sets $! to 10061 in the child process. The parent process will set $! based on the child's exit code\, and thus to 77. This is why the check for ECONNREFUSED fails in the parent process. My solution was to do that check in the child process instead.

Additionally\, I checked that $! \<= 255 in the child process. If this is not the case\, the child exits with code 255. This is just to make sure that 0 is not accidentially returned.

Your patch looks reasonable\, so I have applied it as change#19536.

However\, the $syn_forking code paths are no longer enabled by default\, as I have now reworked the code to use non-blocking sockets. This implementation passes all but one test (including the normally skipped network tests) on Windows 2000. I haven't checked other Windows versions\, but have enabled it as the default to see how it fares in the smoke tests. The failing test appears to be for the ack() code\, which doesn't look all that correct to me. There are all manner of inefficient loops and code that changes variables that aren't used\, etc. I hope whoever wrote it can kindly revisit it.

Sarathy gsar@​ActiveState.com

Inline Patch ```diff -----------------------------------8<----------------------------------- Change 19535 by gsar@zen-gsar on 2003/05/17 05:54:39 improve the implementation of Net::Ping on windows by avoiding fork(), which is pretty heavy-weight for this kind of application; use non-blocking sockets instead has been verified to work on Win2k but will need testing on other flavors of windows there is a single known failure on windows in 450_service.t (test 18) due to what appears to be bugs in the ping_syn()/ack() code Affected files ... ... //depot/perl/lib/Net/Ping.pm#40 edit Differences ... ==== //depot/perl/lib/Net/Ping.pm#40 (text) ==== Index: perl/lib/Net/Ping.pm --- perl/lib/Net/Ping.pm.~1~ Sat May 17 00:27:27 2003 +++ perl/lib/Net/Ping.pm Sat May 17 00:27:27 2003 @@ -8,9 +8,9 @@ $def_timeout $def_proto $def_factor $max_datasize $pingstring $hires $source_verify $syn_forking); use Fcntl qw( F_GETFL F_SETFL O_NONBLOCK ); -use Socket qw( SOCK_DGRAM SOCK_STREAM SOCK_RAW PF_INET SOL_SOCKET +use Socket qw( SOCK_DGRAM SOCK_STREAM SOCK_RAW PF_INET SOL_SOCKET SO_ERROR inet_aton inet_ntoa sockaddr_in ); -use POSIX qw( ECONNREFUSED ECONNRESET EINPROGRESS EAGAIN WNOHANG ); +use POSIX qw( ENOTCONN ECONNREFUSED ECONNRESET EINPROGRESS EWOULDBLOCK EAGAIN WNOHANG ); use FileHandle; use Carp; @@ -33,7 +33,11 @@ # Hack to avoid this Win32 spewage: # Your vendor has not defined POSIX macro ECONNREFUSED *ECONNREFUSED = sub {10061;}; # "Unknown Error" Special Win32 Response? - $syn_forking = 1; + *ENOTCONN = sub {10057;}; + *ECONNRESET = sub {10054;}; + *EINPROGRESS = sub {10036;}; + *EWOULDBLOCK = sub {10035;}; +# $syn_forking = 1; # XXX possibly useful in < Win2K ? }; # h2ph "asm/socket.h" @@ -207,6 +211,32 @@ return 1; } +# Description: A select() wrapper that compensates for platform +# peculiarities. +sub mselect +{ + if ($_[3] > 0 and $^O eq 'MSWin32') { + # On windows, select() doesn't process the message loop, + # but sleep() will, allowing alarm() to interrupt the latter. + # So we chop up the timeout into smaller pieces and interleave + # select() and sleep() calls. + my $t = $_[3]; + my $gran = 0.5; # polling granularity in seconds + my @args = @_; + while (1) { + $gran = $t if $gran > $t; + my $nfound = select($_[0], $_[1], $_[2], $gran); + $t -= $gran; + return $nfound if $nfound or !defined($nfound) or $t <= 0; + + sleep(0); + ($_[0], $_[1], $_[2]) = @args; + } + } + else { + return select($_[0], $_[1], $_[2], $_[3]); + } +} # Description: Allow UDP source endpoint comparision to be # skipped for those remote interfaces that do @@ -272,6 +302,14 @@ # set the non-blocking mode (set O_NONBLOCK) my $flags; + if ($^O eq 'MSWin32') { + # FIONBIO enables non-blocking sockets on windows. + # FIONBIO is (0x80000000|(4<<16)|(ord('f')<<8)|126), as per winsock.h. + my $f = 0x8004667e; + my $v = pack("L", $block ? 0 : 1); + ioctl($fh, $f, $v) or croak("ioctl failed: $!"); + return; + } if ($flags = fcntl($fh, F_GETFL, 0)) { $flags = $block ? ($flags & ~O_NONBLOCK) : ($flags | O_NONBLOCK); if (!fcntl($fh, F_SETFL, $flags)) { @@ -399,7 +437,7 @@ $finish_time = &time() + $timeout; # Must be done by this time while (!$done && $timeout > 0) # Keep trying if we have time { - $nfound = select((my $rout=$rbits), undef, undef, $timeout); # Wait for packet + $nfound = mselect((my $rout=$rbits), undef, undef, $timeout); # Wait for packet $timeout = $finish_time - &time(); # Get remaining time if (!defined($nfound)) # Hmm, a strange error { @@ -537,7 +575,7 @@ if (!connect($self->{"fh"}, $saddr)) { if ($! == ECONNREFUSED) { $ret = 1 unless $self->{"econnrefused"}; - } elsif ($! != EINPROGRESS) { + } elsif ($! != EINPROGRESS && ($^O ne 'MSWin32' || $! != EWOULDBLOCK)) { # EINPROGRESS is the expected error code after a connect() # on a non-blocking socket. But if the kernel immediately # determined that this connect() will never work, @@ -548,11 +586,14 @@ } else { # Got the expected EINPROGRESS. # Just wait for connection completion... - my ($wbits, $wout); - $wout = $wbits = ""; + my ($wbits, $wout, $wexc); + $wout = $wexc = $wbits = ""; vec($wbits, $self->{"fh"}->fileno, 1) = 1; - my $nfound = select(undef, ($wout = $wbits), undef, $timeout); + my $nfound = mselect(undef, + ($wout = $wbits), + ($^O eq 'MSWin32' ? ($wexc = $wbits) : undef), + $timeout); warn("select: $!") unless defined $nfound; if ($nfound && vec($wout, $self->{"fh"}->fileno, 1)) { @@ -576,7 +617,18 @@ && $! == ECONNREFUSED); } } else { - # the connection attempt timed out + # the connection attempt timed out (or there were connect + # errors on Windows) + if ($^O =~ 'MSWin32') { + # If the connect will fail on a non-blocking socket, + # winsock reports ECONNREFUSED as an exception, and we + # need to fetch the socket-level error code via getsockopt() + # instead of using the thread-level error code that is in $!. + if ($nfound && vec($wexc, $self->{"fh"}->fileno, 1)) { + $! = unpack("i", getsockopt($self->{"fh"}, SOL_SOCKET, + SO_ERROR)); + } + } } } } else { @@ -594,6 +646,8 @@ # Buggy Winsock API doesn't allow nonblocking connect. # Hence, if our OS is Windows, we need to create a separate # process to do the blocking connect attempt. + # XXX Above comments are not true at least for Win2K, where + # nonblocking connect works. $| = 1; # Clear buffer prior to fork to prevent duplicate flushing. $self->{'tcp_chld'} = fork; @@ -694,7 +748,7 @@ vec($rout, $self->{"fh"}->fileno(), 1) = 1; } - if(select($rin, $rout, undef, ($time + $timeout) - &time())) { + if(mselect($rin, $rout, undef, ($time + $timeout) - &time())) { if($rout && vec($rout,$self->{"fh"}->fileno(),1)) { my $num = syswrite($self->{"fh"}, $wrstr, length $wrstr); @@ -853,7 +907,7 @@ $timeout = $retrans if $timeout > $retrans; $retrans*= $factor; # Exponential backoff } - $nfound = select((my $rout=$rbits), undef, undef, $timeout); # Wait for response + $nfound = mselect((my $rout=$rbits), undef, undef, $timeout); # Wait for response my $why = $!; $timeout = $finish_time - &time(); # Get remaining time @@ -956,7 +1010,7 @@ #warn "WARNING: Nonblocking connect connected anyway? ($^O)"; } else { # Error occurred connecting. - if ($! == EINPROGRESS) { + if ($! == EINPROGRESS || ($^O eq 'MSWin32' && $! == EWOULDBLOCK)) { # The connection is just still in progress. # This is the expected condition. } else { @@ -1100,7 +1154,7 @@ $fd++; } - if (defined($winner_fd) or my $nfound = select(undef, ($wout=$wbits), undef, $timeout)) { + if (defined($winner_fd) or my $nfound = mselect(undef, ($wout=$wbits), undef, $timeout)) { if (defined $winner_fd) { $fd = $winner_fd; } else { @@ -1204,7 +1258,7 @@ if ($timeout > 0) { my $nfound; while ( keys %{ $self->{"syn"} } and - $nfound = select((my $rout=$rbits), undef, undef, $timeout)) { + $nfound = mselect((my $rout=$rbits), undef, undef, $timeout)) { # Done waiting for one of the ACKs if (!sysread($self->{"fork_rd"}, $_, 16)) { # Socket closed, which means all children are done. End of Patch. ```
p5pRT commented 21 years ago

From rob@roobik.com

On Sat\, 17 May 2003\, Gurusamy Sarathy wrote​:

On Thu\, 15 May 2003 22​:25​:37 +0200\, "Marcus Holland-Moritz" wrote​:

One problem is that in Net​::Ping on MSWin32\, a tcp ping is run in a separate process using fork().

I don't think this is really necessary. Non-blocking connects should work fine on Windows NT (I've checked at least Windows 2000).

Sarathy​:

Yes\, I could never get the non-blocking connect to work under win98 activestate perl 5.6.1. (Though it seems perfectly fine on all cygwin perls.) Maybe a bug in ActiveState's fcntl()? Which perl did you actually get non-blocking connect to work for MSWin32? I'll try 5.8.0 and win2k.

Even though $ret is set in the child process\, $ret is not set in the parent process. As it defaults to 0\, tcp pings are never successful. My solution was to explicitly set $ret in the parent process depending on the exit status (0 on success\, $! on failure) of the child process.

The other problem is that a process exit code must be in the range 0..255. As the child process exits with $!\, if $! is greater than 255\, the exit code will actually be ($! & 255). This does not work if connect() fails with ECONNREFUSED\, which sets $! to 10061 in the child process. The parent process will set $! based on the child's exit code\, and thus to 77. This is why the check for ECONNREFUSED fails in the parent process. My solution was to do that check in the child process instead.

Additionally\, I checked that $! \<= 255 in the child process. If this is not the case\, the child exits with code 255. This is just to make sure that 0 is not accidentially returned.

Your patch looks reasonable\, so I have applied it as change#19536.

Yes\, the other patch fixed a few things and so I applied it to the cvs source tree as well as a few other things for version 2.31​:

cvs -q -d :pserver​:anonymous@​cvs.roobik.com.​:/cvsroot/freeware co Net-Ping cd Net-Ping perl Makefile.PL make make test

This new patch seems a little off against the latest source tree\, but I'll try to apply it manually...

However\, the $syn_forking code paths are no longer enabled by default\, as I have now reworked the code to use non-blocking sockets. This implementation passes all but one test (including the normally skipped network tests) on Windows 2000. I haven't checked other Windows versions\, but have enabled it as the default to see how it fares in the smoke tests. The failing test appears to be for the ack() code\, which doesn't look all that correct to me. There are all manner of inefficient loops and code that changes variables that aren't used\, etc. I hope whoever wrote it can kindly revisit it.

The ack test still failed on win32 for some reason. I only made the $syn_forking code to get around the non-blocking connect deficiencies of activestate's MSWin32 perl. It used to work somehow\, but I guess I'll need to do more testing. The syn/ack tests always work on freebsd\, solaris\, linux\, and cygwin\, with all version of perl that I've tried (5.005\, 5.6.0\, 5.6.1\, 5.8.0). I'll need to add some more work arounds to get it to pass for MSWin32.

-- Rob

p5pRT commented 21 years ago

From @gsar

On Mon\, 19 May 2003 11​:30​:17 MDT\, Rob Brown wrote​:

Sarathy​:

Yes\, I could never get the non-blocking connect to work under win98 activestate perl 5.6.1.

Can you try the new non-blocking code on Windows 9x?

This message from Rocco Caputo suggests non-blocking sockets work fine on Windows 9x.

  http​://archive.develooper.com/perl5-porters@​perl.org/msg62779.html

(BTW\, contrary what he says\, the test code in the above message works fine on Windows 2000 for me (tested with 5.6.1 and bleadperl). Perhaps his problem was the ioctl() bug in 5.8.0 that has now been fixed?)

(Though it seems perfectly fine on all cygwin perls.) Maybe a bug in ActiveState's fcntl()?

There is no fcntl() in the native windows port. CORE​::ioctl() maps to winsock's ioctlsocket() there.

Which perl did you actually get non-blocking connect to work for MSWin32? I'll try 5.8.0 and win2k.

5.8.0 had a bug whereby the return value of ioctl() was broken on some platforms including windows. I fixed this in a recent change (19534). You will need at least that patch if you're trying it with 5.8.0. 5.6.1 probably works without any other patches.

change#19533 may also be useful to see the right $! (errno) after a select().

Note that I only tested my changes against bleadperl with the above patches.

This new patch seems a little off against the latest source tree\, but I'll try to apply it manually...

Probably because you're not using bleadperl? You can rsync it from the location mentioned in perlhack.pod.

However\, the $syn_forking code paths are no longer enabled by default\, as I have now reworked the code to use non-blocking sockets. This implementation passes all but one test (including the normally skipped network tests) on Windows 2000. I haven't checked other Windows versions\, but have enabled it as the default to see how it fares in the smoke tests. The failing test appears to be for the ack() code\, which doesn't look all that correct to me. There are all manner of inefficient loops

I mean code like this​:

  while ($wout !~ /^\0*\z/ &&   !vec($wout\, $fd\, 1)) {   $fd++;   }

$wout never changes in the loop\, so why do the first test repeatedly?

and code that changes variables that aren't used\, etc. I hope whoever wrote it can kindly revisit it.

The ack test still failed on win32 for some reason.

As I mentioned earlier\, 450_service.t#18 fails for me too on windows (with my non-blocking changes). In looking at the failure\, I ran into the ack() code and stopped pursuing it further. ;)

It is probably something that is fixable. I'd guess that the select() inside the ack() function must monitor for exceptions on the list of sockets (windows likes to report "connection refused" as an exception on non-blocking sockets).

I only made the $syn_forking code to get around the non-blocking connect deficiencies of activestate's MSWin32 perl. It used to work somehow\, but I guess I'll need to do more testing. The syn/ack tests always work on freebsd\, solaris\, linux\, and cygwin\, with all version of perl that I've tried (5.005\, 5.6.0\, 5.6.1\, 5.8.0). I'll need to add some more work arounds to get it to pass for MSWin32.

I'm not sure I understand why the ack() function needs to loop through a bit string to find the list of handles when ping_syn() only ever opens a single well-defined handle. If we want to support multiple ping_syn() calls followed by a single ack() that waits for them\, why not maintain the list of filehandles directly in an array\, instead of all this $wbits and vec() complexity? It seems to me that this code could be a lot simpler than it currently is.

Sarathy gsar@​ActiveState.com

p5pRT commented 19 years ago

From @richardfoley

Old installation - superceded by more recent releases.

p5pRT commented 19 years ago

@richardfoley - Status changed from 'open' to 'stalled'

p5pRT commented 16 years ago

From @smpeters

On Thu May 15 13​:26​:29 2003\, mhx-perl@​gmx.net wrote​:

| ../lib/Net/Ping/t/450_service..........NOK 8# Failed test 8 in ../lib/Net/Ping/t/450_service.t at line 77 | # ../lib/Net/Ping/t/450_service.t line 77 is​: ok $p -> ping("127.0.0.1"); | ../lib/Net/Ping/t/450_service..........NOK 9# Failed test 9 in ../lib/Net/Ping/t/450_service.t at line 83 | # ../lib/Net/Ping/t/450_service.t line 83 is​: ok $p -> ping("127.0.0.1"); | ../lib/Net/Ping/t/450_service..........NOK 10# Failed test 10 in ../lib/Net/Ping/t/450_service.t at line 94 | # ../lib/Net/Ping/t/450_service.t line 94 is​: ok $p -> ping("127.0.0.1"); | ../lib/Net/Ping/t/450_service..........FAILED tests 8-10 | Failed 3/26 tests\, 88.46% okay

I think I know why these tests failed and I also have a patch for lib/Net/Ping.pm that fixes the failures. However\, as this is my first patch to a Perl core module\, I'd appreciate it if someone would have a closer look.

One problem is that in Net​::Ping on MSWin32\, a tcp ping is run in a separate process using fork(). Even though $ret is set in the child process\, $ret is not set in the parent process. As it defaults to 0\, tcp pings are never successful. My solution was to explicitly set $ret in the parent process depending on the exit status (0 on success\, $! on failure) of the child process.

The other problem is that a process exit code must be in the range 0..255. As the child process exits with $!\, if $! is greater than 255\, the exit code will actually be ($! & 255). This does not work if connect() fails with ECONNREFUSED\, which sets $! to 10061 in the child process. The parent process will set $! based on the child's exit code\, and thus to 77. This is why the check for ECONNREFUSED fails in the parent process. My solution was to do that check in the child process instead.

Additionally\, I checked that $! \<= 255 in the child process. If this is not the case\, the child exits with code 255. This is just to make sure that 0 is not accidentially returned.

-- Marcus

This patch has been part of the Net​::Ping code for quite some time and seems to be working fine. Thanks!

Steve Peters

p5pRT commented 16 years ago

The RT System itself - Status changed from 'stalled' to 'open'

p5pRT commented 16 years ago

@smpeters - Status changed from 'open' to 'resolved'