summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-02-15 16:33:24 -0800
committerFather Chrysostomos <sprout@cpan.org>2011-02-15 16:34:22 -0800
commit2e0cfa16dea85dd33fe3cbf38f3324f4a8418181 (patch)
tree5189c0767046a1d431bd10c87d9b34efbed4ea04 /util.c
parentc222ef4643569ab52b77652219561edee7a72409 (diff)
downloadperl-2e0cfa16dea85dd33fe3cbf38f3324f4a8418181.tar.gz
[perl #78494] Pipes cause threads to hang on join()
or on close() in either thread. close() in one thread blocks until close() is called in the other thread, because both closes are waiting for the child process to end. Since we have a reference-counting mechanism for the underlying fileno, we can use that to determine whether close() should wait. This does not solve the problem of close $OUT block when it has been duplicated via open $OUT2, ">&" and $OUT2 is still in scope.
Diffstat (limited to 'util.c')
-rw-r--r--util.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/util.c b/util.c
index 22940dd1a9..4b4bfe17e3 100644
--- a/util.c
+++ b/util.c
@@ -25,6 +25,8 @@
#define PERL_IN_UTIL_C
#include "perl.h"
+#include "perliol.h" /* For PerlIOUnix_refcnt */
+
#ifndef PERL_MICRO
#include <signal.h>
#ifndef SIG_ERR
@@ -3118,11 +3120,16 @@ Perl_my_pclose(pTHX_ PerlIO *ptr)
int status;
SV **svp;
Pid_t pid;
- Pid_t pid2;
+ Pid_t pid2 = 0;
bool close_failed;
dSAVEDERRNO;
+ const int fd = PerlIO_fileno(ptr);
+
+ /* Find out whether the refcount is low enough for us to wait for the
+ child proc without blocking. */
+ const bool should_wait = PerlIOUnix_refcnt(fd) == 1;
- svp = av_fetch(PL_fdpid,PerlIO_fileno(ptr),TRUE);
+ svp = av_fetch(PL_fdpid,fd,TRUE);
pid = (SvTYPE(*svp) == SVt_IV) ? SvIVX(*svp) : -1;
SvREFCNT_dec(*svp);
*svp = &PL_sv_undef;
@@ -3141,7 +3148,7 @@ Perl_my_pclose(pTHX_ PerlIO *ptr)
rsignal_save(SIGINT, (Sighandler_t) SIG_IGN, &istat);
rsignal_save(SIGQUIT, (Sighandler_t) SIG_IGN, &qstat);
#endif
- do {
+ if (should_wait) do {
pid2 = wait4pid(pid, &status, 0);
} while (pid2 == -1 && errno == EINTR);
#ifndef PERL_MICRO
@@ -3153,7 +3160,11 @@ Perl_my_pclose(pTHX_ PerlIO *ptr)
RESTORE_ERRNO;
return -1;
}
- return(pid2 < 0 ? pid2 : status == 0 ? 0 : (errno = 0, status));
+ return(
+ should_wait
+ ? pid2 < 0 ? pid2 : status == 0 ? 0 : (errno = 0, status)
+ : 0
+ );
}
#else
#if defined(__LIBCATAMOUNT__)