develooper Front page | perl.perl5.porters | Postings from February 2013

[perl #106212] close and dup hang in threads

Thread Next
From:
Patrik Hagglund via RT
Date:
February 12, 2013 04:10
Subject:
[perl #106212] close and dup hang in threads
Message ID:
rt-3.6.HEAD-27190-1360598165-1737.106212-14-0@perl.org
I have now tried to fix this myself. See patch and updated test-case 
below (or attached files).

However, I'm not sure if I fulfill the requriement in atfork_lock():

/* locks must be held in locking order (if any) */

(Also, I find the comment in atfork_unlock strange, saying that the same 
order should be used, rather than the reverse.)

/Patrik Hägglund

From fb0fe87ffa55b8121f0610b44a9c87fef519a2f0 Mon Sep 17 00:00:00 2001
From: Patrik Hagglund <patrik.h.hagglund@ericsson.com>
Date: Sat, 2 Feb 2013 20:21:05 +0100
Subject: [PATCH] Add PL_perlio_mutex to atfork_lock/unlock, to fix bug
 #106212.
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------1.8.1.3"

This is a multi-part message in MIME format.
--------------1.8.1.3
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit


Using threads + fork() on Linux, and IO operations in the threads, the
PL_perlio_mutex may be left in a locked state at the call of fork(),
potentially leading to deadlock in the child process at subsequent IO
operations. (Threads are pre-empted and not continued in the child
process after the fork.)

Therefore, ensure that the PL_perlio_mutex is unlocked in the child
process, right after fork(), by using atfork_lock/unlock.
---
 util.c | 2 ++
 1 file changed, 2 insertions(+)


--------------1.8.1.3
Content-Type: text/x-patch; name="0001-Add-PL_perlio_mutex-to-
atfork_lock-unlock-to-fix-bug.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0001-Add-PL_perlio_mutex-to-
atfork_lock-unlock-to-fix-bug.patch"

diff --git a/util.c b/util.c
index a3fbd3c..4c25a44 100644
--- a/util.c
+++ b/util.c
@@ -2798,6 +2798,7 @@ Perl_atfork_lock(void)
    dVAR;
 #if defined(USE_ITHREADS)
     /* locks must be held in locking order (if any) */
+    MUTEX_LOCK(&PL_perlio_mutex);
 #  ifdef MYMALLOC
     MUTEX_LOCK(&PL_malloc_mutex);
 #  endif
@@ -2812,6 +2813,7 @@ Perl_atfork_unlock(void)
     dVAR;
 #if defined(USE_ITHREADS)
     /* locks must be released in same order as in atfork_lock() */
+    MUTEX_UNLOCK(&PL_perlio_mutex);
 #  ifdef MYMALLOC
     MUTEX_UNLOCK(&PL_malloc_mutex);
 #  endif

--------------1.8.1.3--

### Reproduce a hang on IO ops, while using threads + fork on Linux.

# Skeleton version of a test driver program utilizing Perl threads.

use threads;

# execute a "test"
sub exec_and_check ($) {
    my ($t) = @_;    
    open(my $tmph, '>', "/tmp/foo$t");
    my $pid = fork();
    if ($pid == 0) {
	# in child
	# test an IO op, in this case 'close' => hangs sometimes
        close($tmph);
	### excecute (here a dummy cmd)
        exec('true');
    }
    # in parent
    waitpid($pid, 0);
}

# run a number of "tests" sequentially
sub runtest_vary ($) {
    my ($t) = @_;
    for (my $i = 0; $i < 80; ++$i) {
        exec_and_check($t);
    }
}

# wait for thread completion
sub threads_wait () {
    for (; threads->list() > 0;) {
        for (;;sleep(1)) {
            my @thrs = threads->list(threads::joinable);
            if (@thrs > 0) {
		my $tid = $thrs[0]->tid();
		print "thread $tid finished\n";
                $thrs[0]->join();
                last;
            } else {
	    # for debug: print "hangs"
		my @t = threads->list();
		print "@t\n";
	    }
        }
    }
}

# run all
for (my $t = 0; $t < 10; ++$t) {
    threads->create(\&runtest_vary, $t);
}
threads_wait();

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About