New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lock ordering issue; deadlock in malloc()/Perl_atfork_lock() #13687
Comments
From prumpf@gmail.comCreated by prumpf@gmail.comThis is a bug report for perl from prumpf@gmail.com, ----------------------------------------------------------------- Hi! I've run into a deadlock situation with the current git versions In summary, the problem is inconsistent lock ordering between Perl's Perl runs pthread_atfork before the first malloc() makes glibc install However, Perl's malloc implementation locks PL_malloc_mutex first, I believe this is fundamentally a glibc bug: its implementation of The workaround should be as easy as including an extra Nevertheless, I'll include it here, because most of the work was diff --git a/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm Perl Info
|
From prumpf@gmail.comperl-deadlock-workaround.diffdiff --git a/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm b/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
index 730c565..a8092bf 100644
--- a/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
+++ b/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
@@ -129,6 +129,19 @@ main(int argc, char **argv, char **env)
* call PTHREAD_ATFORK() explicitly, but if and only if it hasn't
* been called at least once before in the current process.
* --GSAR 2001-07-20 */
+ /* There's a nasty race condition with the current versions of Perl and
+ * glibc: the call to PTHREAD_ATFORK in Perl's main() might be reached
+ * before the first malloc happens, in which
+ * case fork() locks malloc/arena.c's list_lock first, then tries to lock
+ * PL_malloc_lock; another thread might have locked PL_malloc_lock first,
+ * then tries to lock list_lock, resulting in a deadlock.
+ *
+ * A proper fix would be in glibc, ensuring that ptmalloc_init() is called
+ * earlier, but a workaround is to make a malloc call ourselves. */
+ /* This leaks memory, but works. */
+ (void)perl_alloc();
+ /* This doesn't leak memory, but is optimized away by gcc */
+ PerlMem_free(PerlMem_malloc(1024));
PTHREAD_ATFORK(Perl_atfork_lock,
Perl_atfork_unlock,
Perl_atfork_unlock);
|
From @tonycozOn Sat Mar 22 09:53:21 2014, prumpf@gmail.com wrote:
Have you reported the glibc part of the problem to your vendor (Debian?) Since this seems to be a glibc specific issue, I wonder if there's a glibc specific way of forcing initialization. In any case, the workaround would need to be protected by #ifdef __GLIBC__ https://bugzilla.redhat.com/show_bug.cgi?id=906468 seems like a different but related issue, unfortunately his post to the glibc mailing list: https://sourceware.org/ml/libc-alpha/2013-01/msg01051.html seems to have been ignored. Tony |
The RT System itself - Status changed from 'new' to 'open' |
From @LeontOn Sat, Mar 22, 2014 at 5:53 PM, Philipp Rumpf <perlbug-followup@perl.org>wrote:
This doesn't make sense. Perl's malloc should only use the system's malloc Leon |
From @LeontOn Sat, Mar 29, 2014 at 3:46 PM, Philipp Rumpf <prumpf@gmail.com> wrote:
Yet I don't think pretending that at_fork is helpful at all. That will only
Yes that makes sense. I guess that means your original proposed solution Leon |
From prumpf@gmail.comThanks for your response! On Wed, Mar 26, 2014 at 6:47 AM, Tony Cook via RT <perlbug-followup@perl.org
I confirmed the problem is present in the git version of glibc and reported
How about simply forcing HAS_PTHREAD_ATFORK to undef if __GLIBC__ is Ideally, there would be a test case to determine at configuration time Here's what I've come up with, as a patch against metaconfig: Inline Patchdiff --git a/U/threads/d_pthread_atfork.U b/U/threads/d_pthread_atfork.U
index 77a8b43..9f0332a 100644
--- a/U/threads/d_pthread_atfork.U
+++ b/U/threads/d_pthread_atfork.U
@@ -5,7 +5,7 @@
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
-?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar
+?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar d_gnulibc
?MAKE: -pick add $@ %<
?S:d_pthread_atfork:
?S: This variable conditionally defines the HAS_PTHREAD_ATFORK symbol,
@@ -37,6 +37,12 @@ if eval $compile; then
else
val="$undef"
fi
+case "$d_gnulibc" in
+*)
+ echo "Assuming pthread_atfork is broken, since this is glibc."
+ val="$undef"
+ ;;
+esac
case "$usethreads" in
$define)
case "$val" in
I don't fully understand that report; it sounds like malloc_atfork() Anyway, I think that's a different issue, though it's a pity if it hasn't |
From prumpf@gmail.commetaconfig-broken-pthread_atfork.diffdiff --git a/U/threads/d_pthread_atfork.U b/U/threads/d_pthread_atfork.U
index 77a8b43..9f0332a 100644
--- a/U/threads/d_pthread_atfork.U
+++ b/U/threads/d_pthread_atfork.U
@@ -5,7 +5,7 @@
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
-?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar
+?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar d_gnulibc
?MAKE: -pick add $@ %<
?S:d_pthread_atfork:
?S: This variable conditionally defines the HAS_PTHREAD_ATFORK symbol,
@@ -37,6 +37,12 @@ if eval $compile; then
else
val="$undef"
fi
+case "$d_gnulibc" in
+*)
+ echo "Assuming pthread_atfork is broken, since this is glibc."
+ val="$undef"
+ ;;
+esac
case "$usethreads" in
$define)
case "$val" in
|
From prumpf@gmail.comSorry, I hadn't noticed that PURIFY was still set in my configuration, Hope that helps you make sense of it, and sorry for the confusion. On Wed, Mar 26, 2014 at 10:51 AM, Leon Timmermans via RT <
|
From prumpf@gmail.comHello, As a reminder, the bug is specific to glibc/nptl-based systems with I've reported the issue on the glibc bugzilla after verifying it's not Here's a much simpler fix/workaround, to metaconfig, that we can use until Inline Patchdiff --git a/U/threads/d_pthread_atfork.U b/U/threads/d_pthread_atfork.U
index 77a8b43..9f0332a 100644
--- a/U/threads/d_pthread_atfork.U
+++ b/U/threads/d_pthread_atfork.U
@@ -5,7 +5,7 @@
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
-?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar
+?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar d_gnulibc
?MAKE: -pick add $@ %<
?S:d_pthread_atfork:
?S: This variable conditionally defines the HAS_PTHREAD_ATFORK symbol,
@@ -37,6 +37,12 @@ if eval $compile; then
else
val="$undef"
fi
+case "$d_gnulibc" in
+*)
+ echo "Assuming pthread_atfork is broken, since this is glibc."
+ val="$undef"
+ ;;
+esac
case "$usethreads" in
$define)
case "$val" in
-------------------------------------------
#!/usr/bin/perl use threads; async { for (my $i = 0; ; $i++) { sleep(1); To force the deadlock, set a breakpoint in S_more_refcounted_fds, then wait As you can see in this rather long GDB transcript, the bug is what I Sorry again for the -DPURIFY confusion. Philipp Rumpf GDB transcript: This is free software: you are free to change and redistribute it. Breakpoint 1, PerlIOUnix_refcnt_inc (fd=0) at perlio.c:2372 Breakpoint 1, PerlIOUnix_refcnt_inc (fd=16) at perlio.c:2372 (gdb) thr app all bt Thread 2 (Thread 0x7ffff6b3c700 (LWP 19621)): Thread 1 (Thread 0x7ffff7fd3700 (LWP 19619)): |
From prumpf@gmail.commetaconfig-broken-pthread_atfork.diffdiff --git a/U/threads/d_pthread_atfork.U b/U/threads/d_pthread_atfork.U
index 77a8b43..9f0332a 100644
--- a/U/threads/d_pthread_atfork.U
+++ b/U/threads/d_pthread_atfork.U
@@ -5,7 +5,7 @@
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
-?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar
+?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar d_gnulibc
?MAKE: -pick add $@ %<
?S:d_pthread_atfork:
?S: This variable conditionally defines the HAS_PTHREAD_ATFORK symbol,
@@ -37,6 +37,12 @@ if eval $compile; then
else
val="$undef"
fi
+case "$d_gnulibc" in
+*)
+ echo "Assuming pthread_atfork is broken, since this is glibc."
+ val="$undef"
+ ;;
+esac
case "$usethreads" in
$define)
case "$val" in
|
From @TuxOn Sat, 29 Mar 2014 14:46:08 +0000, Philipp Rumpf <prumpf@gmail.com>
I admire the fact that this is a genuine patch to the meta-system, but
-- |
From prumpf@gmail.comOn Mon, Mar 31, 2014 at 6:28 AM, H. Merijn Brand via RT <
I don't know. The build system is a bit of a mystery to me (I'm not sure, There are four options here: put the test in metaconfig or the hints file, I'd argue that the code with the test program might well go into So I've attached the two test-program-based versions, as patches to Philipp
|
From prumpf@gmail.comperl-hints-002.diffdiff --git a/hints/linux.sh b/hints/linux.sh
index 956adfc..d1e2737 100644
--- a/hints/linux.sh
+++ b/hints/linux.sh
@@ -516,3 +516,104 @@ case "$libdb_needs_pthread" in
libswanted="$libswanted pthread"
;;
esac
+
+cat >try.c <<'EOM'
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int pipe_fd[4];
+
+void lock(void)
+{
+ if (write(pipe_fd[3], "\n", 1) <= 0) {
+ _exit(1);
+ }
+ pthread_mutex_lock(&mutex);
+}
+
+void *lock_then_malloc(void *dummy)
+{
+ char c;
+
+ pthread_mutex_lock(&mutex);
+ if (write(pipe_fd[1], "\n", 1) <= 0) {
+ _exit(1);
+ }
+
+ if (read(pipe_fd[2], &c, 1) <= 0) {
+ _exit(1);
+ }
+ volatile void *throwaway = malloc(1024);
+ pthread_mutex_unlock(&mutex);
+
+ return NULL;
+}
+
+void alarm_handler(int dummy)
+{
+ _exit(1);
+}
+
+struct sigaction sa;
+
+int main(int argc, char **argv)
+{
+ pthread_attr_t attr;
+ pthread_t tid;
+
+ if (pthread_atfork(lock, NULL, NULL)) {
+ return 1;
+ }
+ volatile void *throwaway = malloc(1024);
+
+ if (pipe(pipe_fd)) {
+ return 1;
+ }
+
+ if (pipe(pipe_fd+2)) {
+ return 1;
+ }
+
+ if (pthread_attr_init(&attr)) {
+ return 1;
+ }
+ if (pthread_create(&tid, &attr, lock_then_malloc, NULL)) {
+ return 1;
+ }
+
+ char c;
+ if (read(pipe_fd[0], &c, 1) <= 0) {
+ return 1;
+ }
+
+ sa.sa_handler = alarm_handler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGALRM, &sa, NULL)) {
+ return 1;
+ }
+ alarm(2);
+
+ if (fork() < 0)
+ return 1;
+
+ return 0;
+}
+EOM
+
+if ${cc:-gcc} $ccflags $ldflags try.c -lpthread >/dev/null 2>&1 && $run ./a.out; then
+ cat <<'EOM' >&4
+
+You appear to have a working pthread_atfork().
+EOM
+else
+ cat <<'EOM' >&4
+
+Your pthread_atfork() might be broken, not using it.
+EOM
+ d_pthread_atfork='undef'
+fi
|
From prumpf@gmail.commetaconfig-pthread-002.diffdiff --git a/U/threads/d_pthread_atfork.U b/U/threads/d_pthread_atfork.U
index 77a8b43..2a84eac 100644
--- a/U/threads/d_pthread_atfork.U
+++ b/U/threads/d_pthread_atfork.U
@@ -1,11 +1,13 @@
?RCS: $Id$
?RCS:
?RCS: Copyright (c) 2001 Jarkko Hietaniemi
+?RCS: Parts taken from d_pthreadj.U, which is:
+?RCS: Copyright (c) 1998 Andy Dougherty
?RCS:
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
-?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar
+?MAKE:d_pthread_atfork: Inlibc cat Compile Setvar run rm
?MAKE: -pick add $@ %<
?S:d_pthread_atfork:
?S: This variable conditionally defines the HAS_PTHREAD_ATFORK symbol,
@@ -19,30 +21,112 @@
?H:#$d_pthread_atfork HAS_PTHREAD_ATFORK /**/
?H:.
?LINT:set d_pthread_atfork
-: see whether the pthread_atfork exists
-$cat >try.c <<EOP
-#include <pthread.h>
+?T:yyy
+?F:!try
+: see whether pthread_atfork exists and works
+echo "Checking whether pthread_atfork is usable..." >&4
+$cat >try.c <<'EOP'
#include <stdio.h>
-int main() {
-#ifdef PTHREAD_ATFORK
- pthread_atfork(NULL,NULL,NULL);
-#endif
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int pipe_fd[4];
+
+void lock(void)
+{
+ if (write(pipe_fd[3], "\n", 1) <= 0) {
+ _exit(1);
+ }
+ pthread_mutex_lock(&mutex);
+}
+
+void *lock_then_malloc(void *dummy)
+{
+ char c;
+
+ pthread_mutex_lock(&mutex);
+ if (write(pipe_fd[1], "\n", 1) <= 0) {
+ _exit(1);
+ }
+
+ if (read(pipe_fd[2], &c, 1) <= 0) {
+ _exit(1);
+ }
+ volatile void *throwaway = malloc(1024);
+ pthread_mutex_unlock(&mutex);
+
+ return NULL;
+}
+
+void alarm_handler(int dummy)
+{
+ _exit(1);
+}
+
+struct sigaction sa;
+
+int main(int argc, char **argv)
+{
+ pthread_attr_t attr;
+ pthread_t tid;
+
+ if (pthread_atfork(lock, NULL, NULL)) {
+ return 1;
+ }
+ volatile void *throwaway = malloc(1024);
+
+ if (pipe(pipe_fd)) {
+ return 1;
+ }
+
+ if (pipe(pipe_fd+2)) {
+ return 1;
+ }
+
+ if (pthread_attr_init(&attr)) {
+ return 1;
+ }
+ if (pthread_create(&tid, &attr, lock_then_malloc, NULL)) {
+ return 1;
+ }
+
+ char c;
+ if (read(pipe_fd[0], &c, 1) <= 0) {
+ return 1;
+ }
+
+ sa.sa_handler = alarm_handler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGALRM, &sa, NULL)) {
+ return 1;
+ }
+ alarm(2);
+
+ int ret = fork();
+ if (ret < 0)
+ return 1;
+
+ if (ret == 0)
+ printf("success\n");
+ return 0;
}
EOP
-: see if pthread_atfork exists
-set try -DPTHREAD_ATFORK
+: see if pthread_atfork exists and works
+set try
if eval $compile; then
- val="$define"
+ yyy=`$run ./try`
else
val="$undef"
fi
-case "$usethreads" in
-$define)
- case "$val" in
- $define) echo 'pthread_atfork found.' >&4 ;;
- *) echo 'pthread_atfork NOT found.' >&4 ;;
- esac
+$rm -f try try.*
+case "$yyy" in
+ success) echo "It does work." >&4; val="$define" ;;
+ *) echo "Doesn't work." >&4; val="$undef" ;;
esac
set d_pthread_atfork
eval $setvar
|
From @LeontOn Tue, Apr 1, 2014 at 5:12 PM, Philipp Rumpf <prumpf@gmail.com> wrote:
But you now introduced exactly the deadlock that the use of pthread_at_fork This is not a solution in any way. Leon |
From prumpf@gmail.comIf HAS_PTHREAD_ATFORK is undefined, Perl_my_fork() calls the same handlers If the malloc hack is considered the better workaround, we can do that, of On Thu, Apr 3, 2014 at 5:48 PM, Leon Timmermans via RT <
|
From prumpf@gmail.comIf it's possible to add a configuration variable in hints/linux.sh, I On Thu, Apr 3, 2014 at 10:15 PM, Philipp Rumpf <prumpf@gmail.com> wrote:
|
From prumpf@gmail.comperl-deadlock-workaround-004.diffdiff --git a/cpan/Devel-PPPort/parts/embed.fnc b/cpan/Devel-PPPort/parts/embed.fnc
index e076893..b8ba5c0 100644
--- a/cpan/Devel-PPPort/parts/embed.fnc
+++ b/cpan/Devel-PPPort/parts/embed.fnc
@@ -877,6 +877,7 @@ Apr |void |my_exit |U32 status
Apr |void |my_failure_exit
Ap |I32 |my_fflush_all
Anp |Pid_t |my_fork
+np |void |atfork_fix
Anp |void |atfork_lock
Anp |void |atfork_unlock
Apmb |I32 |my_lstat
diff --git a/embed.fnc b/embed.fnc
index 567e587..16615e8 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -898,6 +898,7 @@ Apr |void |my_exit |U32 status
Apr |void |my_failure_exit
Ap |I32 |my_fflush_all
Anp |Pid_t |my_fork
+np |void |atfork_fix
Anp |void |atfork_lock
Anp |void |atfork_unlock
Apmb |I32 |my_lstat
diff --git a/embed.h b/embed.h
index 0ddaca7..18c02f1 100644
--- a/embed.h
+++ b/embed.h
@@ -1027,6 +1027,7 @@
#define allocmy(a,b,c) Perl_allocmy(aTHX_ a,b,c)
#define amagic_is_enabled(a) Perl_amagic_is_enabled(aTHX_ a)
#define apply(a,b,c) Perl_apply(aTHX_ a,b,c)
+#define atfork_fix Perl_atfork_fix
#define av_extend_guts(a,b,c,d,e) Perl_av_extend_guts(aTHX_ a,b,c,d,e)
#define bind_match(a,b,c) Perl_bind_match(aTHX_ a,b,c)
#define block_end(a,b) Perl_block_end(aTHX_ a,b)
diff --git a/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm b/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
index 730c565..b486e20 100644
--- a/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
+++ b/ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
@@ -129,6 +129,9 @@ main(int argc, char **argv, char **env)
* call PTHREAD_ATFORK() explicitly, but if and only if it hasn't
* been called at least once before in the current process.
* --GSAR 2001-07-20 */
+#ifdef USE_PTHREAD_ATFORK_MALLOC_HACK
+ Perl_atfork_fix();
+#endif
PTHREAD_ATFORK(Perl_atfork_lock,
Perl_atfork_unlock,
Perl_atfork_unlock);
diff --git a/proto.h b/proto.h
index dd5edde..bbba40a 100644
--- a/proto.h
+++ b/proto.h
@@ -140,6 +140,7 @@ PERL_CALLCONV void Perl_apply_attrs_string(pTHX_ const char *stashpv, CV *cv, co
#define PERL_ARGS_ASSERT_APPLY_ATTRS_STRING \
assert(stashpv); assert(cv); assert(attrstr)
+PERL_CALLCONV void Perl_atfork_fix(void);
PERL_CALLCONV void Perl_atfork_lock(void);
PERL_CALLCONV void Perl_atfork_unlock(void);
PERL_CALLCONV SV** Perl_av_arylen_p(pTHX_ AV *av)
diff --git a/util.c b/util.c
index a5451c1..df26259 100644
--- a/util.c
+++ b/util.c
@@ -2569,6 +2569,19 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode)
#endif /* !DOSISH */
+#ifdef USE_PTHREAD_ATFORK_MALLOC_HACK
+/* needs to be global so GCC doesn't optimize away the malloc() */
+void *pthread_atfork_fix_pointer;
+
+void Perl_atfork_fix(void)
+{
+ /* To avoid a deadlock situation, glibc's malloc must be initialized
+ * before we call pthread_atfork. We can't just use (void)malloc(0)
+ * because GCC removes such calls. */
+ pthread_atfork_fix_pointer = malloc(0);
+}
+#endif
+
/* this is called in parent before the fork() */
void
Perl_atfork_lock(void)
|
From prumpf@gmail.commetaconfig-pthread-004.diffdiff --git a/U/threads/d_pthread_atfork.U b/U/threads/d_pthread_atfork.U
index 77a8b43..2cc9eca 100644
--- a/U/threads/d_pthread_atfork.U
+++ b/U/threads/d_pthread_atfork.U
@@ -1,24 +1,38 @@
?RCS: $Id$
?RCS:
?RCS: Copyright (c) 2001 Jarkko Hietaniemi
+?RCS: Parts taken from d_pthreadj.U, which is:
+?RCS: Copyright (c) 1998 Andy Dougherty
?RCS:
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
-?MAKE:d_pthread_atfork: Inlibc cat Compile usethreads Setvar
+?MAKE:d_pthread_atfork d_pthread_atfork_malloc_hack: Inlibc cat Compile Setvar run rm usethreads
?MAKE: -pick add $@ %<
?S:d_pthread_atfork:
?S: This variable conditionally defines the HAS_PTHREAD_ATFORK symbol,
?S: which indicates to the C program that the pthread_atfork()
?S: routine is available.
?S:.
+?S:d_pthread_atfork_malloc_hack:
+?S: This variable conditionally defines the USE_PTHREAD_ATFORK_MALLOC_HACK
+?S: symbol, which indicates to the C program that malloc() needs to be
+?S: called before pthread_atfork() is.
+?S:.
?C:HAS_PTHREAD_ATFORK:
?C: This symbol, if defined, indicates that the pthread_atfork routine
?C: is available to setup fork handlers.
?C:.
+?C:USE_PTHREAD_ATFORK_MALLOC_HACK:
+?C: This symbol, if defined, indicates that pthread_atfork is broken
+?C: unless malloc is called before it.
+?C:.
?H:#$d_pthread_atfork HAS_PTHREAD_ATFORK /**/
+?H:#$d_pthread_atfork_malloc_hack USE_PTHREAD_ATFORK_MALLOC_HACK /**/
?H:.
-?LINT:set d_pthread_atfork
+?LINT:set d_pthread_atfork d_pthread_atfork_malloc_hack
+?T:yyy
+?F:!try
: see whether the pthread_atfork exists
$cat >try.c <<EOP
#include <pthread.h>
@@ -47,3 +61,113 @@ esac
set d_pthread_atfork
eval $setvar
+: see whether pthread_atfork exists and works
+echo "Checking whether pthread_atfork requires a workaround..." >&4
+$cat >try.c <<'EOP'
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int pipe_fd[4];
+
+void lock(void)
+{
+ if (write(pipe_fd[3], "\n", 1) <= 0) {
+ _exit(1);
+ }
+ pthread_mutex_lock(&mutex);
+}
+
+/* This needs to be a global variable, or GCC gets clever on us
+ * and throws out the malloc() call. */
+volatile void *throwaway;
+
+void *lock_then_malloc(void *dummy)
+{
+ char c;
+
+ pthread_mutex_lock(&mutex);
+ if (write(pipe_fd[1], "\n", 1) <= 0) {
+ _exit(1);
+ }
+
+ if (read(pipe_fd[2], &c, 1) <= 0) {
+ _exit(1);
+ }
+ throwaway = malloc(1024);
+ pthread_mutex_unlock(&mutex);
+
+ return NULL;
+}
+
+void alarm_handler(int dummy)
+{
+ _exit(1);
+}
+
+struct sigaction sa;
+
+int main(int argc, char **argv)
+{
+ pthread_attr_t attr;
+ pthread_t tid;
+ char c;
+ int ret;
+
+ if (pthread_atfork(lock, NULL, NULL)) {
+ return 1;
+ }
+
+ if (pipe(pipe_fd)) {
+ return 1;
+ }
+
+ if (pipe(pipe_fd+2)) {
+ return 1;
+ }
+
+ if (pthread_attr_init(&attr)) {
+ return 1;
+ }
+ if (pthread_create(&tid, &attr, lock_then_malloc, NULL)) {
+ return 1;
+ }
+
+ if (read(pipe_fd[0], &c, 1) <= 0) {
+ return 1;
+ }
+
+ sa.sa_handler = alarm_handler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGALRM, &sa, NULL)) {
+ return 1;
+ }
+ alarm(2);
+
+ ret = fork();
+ if (ret < 0)
+ return 1;
+
+ if (ret == 0)
+ printf("success\n");
+ return 0;
+}
+EOP
+
+: see if pthread_atfork exists and works
+set try
+if eval $compile; then
+ yyy=`$run ./try`
+fi
+$rm -f try try.*
+case "$yyy" in
+ success) echo "It does work without a workaround." >&4; val="$undef" ;;
+ *) echo "Workaround required." >&4; val="$define" ;;
+esac
+set d_pthread_atfork_malloc_hack
+eval $setvar
+
|
Migrated from rt.perl.org#121490 (status was 'open')
Searchable as RT121490$
The text was updated successfully, but these errors were encountered: