Skip Menu |

This queue is for tickets about the File-Tee CPAN distribution.

Report information
The Basics
Id: 101278
Status: open
Priority: 0/
Queue: File-Tee

People
Owner: Nobody in particular
Requestors: SREZIC [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.07
Fixed in: (no value)



Subject: Race condition in test suite?
Test results look quite random, see http://matrix.cpantesters.org/?dist=File-Tee I wonder if there's a race condition somewhere?
On 2015-01-04 04:54:17, SREZIC wrote: Show quoted text
> Test results look quite random, see > http://matrix.cpantesters.org/?dist=File-Tee > I wonder if there's a race condition somewhere?
One possible fail pattern looks like this: $ perl5.18.2 -Mblib t/File-Tee.t 1..50 ok 1 ok 2 - print 0 t ok 3 - print 0 c $ echo $? 141 This is SIGPIPE on this system (freebsd 9.2). Looking with ktrace & kdump on such a test run shows the following: 26366 perl5.18.2 1460206754.114928 CALL fork 26366 perl5.18.2 1460206754.115586 RET fork 26367/0x66ff ... 26366 perl5.18.2 1460206754.135027 GIO fd 6 wrote 17 bytes "ok 2 - print 0 t " 26366 perl5.18.2 1460206754.135108 RET write 17/0x11 26366 perl5.18.2 1460206754.135825 CALL kill(0x66ff,SIGINT) 26366 perl5.18.2 1460206754.135875 RET kill 0 26367 perl5.18.2 1460206754.136037 RET fork 0 26367 perl5.18.2 1460206754.136065 PSIG SIGINT SIG_DFL code=0x10001 ... 26366 perl5.18.2 1460206754.140242 GIO fd 6 wrote 17 bytes "ok 3 - print 0 c " 26366 perl5.18.2 1460206754.140297 RET write 17/0x11 26366 perl5.18.2 1460206754.140959 CALL write(0x3,0x8014a6000,0x10) 26366 perl5.18.2 1460206754.141228 RET write -1 errno 32 Broken pipe 26366 perl5.18.2 1460206754.141430 PSIG SIGPIPE SIG_DFL code=0x10006 So it seems that the completion of the fork() call is quite slow in this case. Setting $SIG{INT} to IGNORE did not happen yet in the child, so it was unexpectedly killed, and the next write() call caused a SIGPIPE in the parent. Not sure what's the best fix here. One could set $SIG{INT} already in the parent before forking, and then undo this setting after the fork() was done. Or wait until the child is really settled before sending the SIGINT --- e.g. by waiting until the process title is changed to "perl [File::Tee]" (on systems where this is supported --- but probably this needs extra tool support e.g. using Proc::ProcessTable). Or just sleep() a little bit...
From: ntyni [...] iki.fi
On Sat Apr 09 09:11:43 2016, SREZIC wrote: Show quoted text
> On 2015-01-04 04:54:17, SREZIC wrote:
> > Test results look quite random, see > > http://matrix.cpantesters.org/?dist=File-Tee > > I wonder if there's a race condition somewhere?
Show quoted text
> So it seems that the completion of the fork() call is quite slow in > this case. Setting $SIG{INT} to IGNORE did not happen yet in the > child, so it was unexpectedly killed, and the next write() call caused > a SIGPIPE in the parent.
Indeed. The attached patch fixes it for me by making a synchronization pipe that the child closes when it's ready. -- Niko Tyni ntyni@debian.org
Subject: 0002-Fix-a-race-condition-with-the-SIGINT-handler.patch
From 8e896957bc0580b53f74152647265a5ea2cdbdf6 Mon Sep 17 00:00:00 2001 From: Niko Tyni <ntyni@debian.org> Date: Tue, 3 Jan 2017 13:54:52 +0000 Subject: [PATCH] Fix a race condition with the SIGINT handler The parent now waits until the child is ready before proceeding. This fixes sporadic test failures in t/File-Tee.t. Bug-Debian: https://bugs.debian.org/834912 Bug: https://rt.cpan.org/Public/Bug/Display.html?id=101278 --- lib/File/Tee.pm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/File/Tee.pm b/lib/File/Tee.pm index caa4ae2..075a9f7 100644 --- a/lib/File/Tee.pm +++ b/lib/File/Tee.pm @@ -149,15 +149,23 @@ sub tee (*;@) { $| = $oldstate[0]; select $oldsel; + my ($readp, $writep); + pipe ($readp, $writep) + or croak "Failed to make a pipe for synchronizing"; + my $pid = open $fh, '|-'; unless ($pid) { defined $pid or return undef; + close $readp; # this end is not for us + $SIG{INT} = 'IGNORE'; undef @ARGV; eval { $0 = "perl [File::Tee]" }; + close $writep; # signal the parent we're ready + my $error = 0; my $oldsel = select STDERR; @@ -252,6 +260,11 @@ sub tee (*;@) { _exit($error); } + close $writep; # this end is not for us + + sysread($readp, my $buf, 256); # should block until the kid is ready + close $readp; + # close $teefh; $oldsel = select($fh); -- 2.11.0