From: Vincent Pit Date: Mon, 29 Sep 2014 14:13:13 +0000 (+0200) Subject: Don't cleanup thread local storage before END blocks are executed X-Git-Tag: rt99083^0 X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2Findirect.git;a=commitdiff_plain;h=640ff2586796fa381d8441b87aa635c5fb2a3170;hp=8eb21ccddb7d9f4040f3ec9069cf013c4d6f4a51 Don't cleanup thread local storage before END blocks are executed reap.h is no longer necessary. This fixes RT #99083. --- diff --git a/MANIFEST b/MANIFEST index 4a583e9..f131bff 100644 --- a/MANIFEST +++ b/MANIFEST @@ -7,7 +7,6 @@ README indirect.xs lib/indirect.pm ptable.h -reap.h samples/indirect.pl t/00-load.t t/10-args.t diff --git a/indirect.xs b/indirect.xs index 511d9cd..db56379 100644 --- a/indirect.xs +++ b/indirect.xs @@ -323,8 +323,6 @@ STATIC void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) { ptable_hints_store(ud->tbl, ent->key, h2); } -#include "reap.h" - STATIC void indirect_thread_cleanup(pTHX_ void *ud) { dMY_CXT; @@ -333,6 +331,29 @@ STATIC void indirect_thread_cleanup(pTHX_ void *ud) { ptable_hints_free(MY_CXT.tbl); } +STATIC int indirect_endav_free(pTHX_ SV *sv, MAGIC *mg) { + SAVEDESTRUCTOR_X(indirect_thread_cleanup, NULL); + + return 0; +} + +STATIC MGVTBL indirect_endav_vtbl = { + 0, + 0, + 0, + 0, + indirect_endav_free +#if MGf_COPY + , 0 +#endif +#if MGf_DUP + , 0 +#endif +#if MGf_LOCAL + , 0 +#endif +}; + #endif /* I_THREADSAFE */ #if I_WORKAROUND_REQUIRE_PROPAGATION @@ -995,6 +1016,7 @@ PROTOTYPE: DISABLE PREINIT: ptable *t; SV *global_code_dup; + GV *gv; PPCODE: { my_cxt_t ud; @@ -1011,7 +1033,23 @@ PPCODE: MY_CXT.owner = aTHX; MY_CXT.global_code = global_code_dup; } - reap(3, indirect_thread_cleanup, NULL); + gv = gv_fetchpv(__PACKAGE__ "::_THREAD_CLEANUP", 0, SVt_PVCV); + if (gv) { + CV *cv = GvCV(gv); + if (!PL_endav) + PL_endav = newAV(); + SvREFCNT_inc(cv); + if (!av_store(PL_endav, av_len(PL_endav) + 1, (SV *) cv)) + SvREFCNT_dec(cv); + sv_magicext((SV *) PL_endav, NULL, PERL_MAGIC_ext, &indirect_endav_vtbl, NULL, 0); + } + XSRETURN(0); + +void +_THREAD_CLEANUP(...) +PROTOTYPE: DISABLE +PPCODE: + indirect_thread_cleanup(aTHX_ NULL); XSRETURN(0); #endif diff --git a/reap.h b/reap.h deleted file mode 100644 index 8db64ed..0000000 --- a/reap.h +++ /dev/null @@ -1,81 +0,0 @@ -/* This file is part of the indirect Perl module. - * See http://search.cpan.org/dist/indirect/ */ - -/* This header provides a specialized version of Scope::Upper::reap that can be - * called directly from XS. - * See http://search.cpan.org/dist/Scope-Upper/ for details. */ - -#ifndef REAP_H -#define REAP_H 1 - -#define REAP_DESTRUCTOR_SIZE 3 - -typedef struct { - I32 depth; - I32 *origin; - void (*cb)(pTHX_ void *); - void *ud; - char *dummy; -} reap_ud; - -STATIC void reap_pop(pTHX_ void *); - -STATIC void reap_pop(pTHX_ void *ud_) { - reap_ud *ud = ud_; - I32 depth, *origin, mark, base; - - depth = ud->depth; - origin = ud->origin; - mark = origin[depth]; - base = origin[depth - 1]; - - if (base < mark) { - PL_savestack_ix = mark; - leave_scope(base); - } - PL_savestack_ix = base; - - if ((ud->depth = --depth) > 0) { - SAVEDESTRUCTOR_X(reap_pop, ud); - } else { - void (*cb)(pTHX_ void *) = ud->cb; - void *cb_ud = ud->ud; - - PerlMemShared_free(ud->origin); - PerlMemShared_free(ud); - - SAVEDESTRUCTOR_X(cb, cb_ud); - } -} - -STATIC void reap(pTHX_ I32 depth, void (*cb)(pTHX_ void *), void *cb_ud) { -#define reap(D, CB, UD) reap(aTHX_ (D), (CB), (UD)) - reap_ud *ud; - I32 i; - - if (depth > PL_scopestack_ix) - depth = PL_scopestack_ix; - - ud = PerlMemShared_malloc(sizeof *ud); - ud->depth = depth; - ud->origin = PerlMemShared_malloc((depth + 1) * sizeof *ud->origin); - ud->cb = cb; - ud->ud = cb_ud; - ud->dummy = NULL; - - for (i = depth; i >= 1; --i) { - I32 j = PL_scopestack_ix - i; - ud->origin[depth - i] = PL_scopestack[j]; - PL_scopestack[j] += REAP_DESTRUCTOR_SIZE; - } - ud->origin[depth] = PL_savestack_ix; - - while (PL_savestack_ix + REAP_DESTRUCTOR_SIZE - <= PL_scopestack[PL_scopestack_ix - 1]) { - save_pptr(&ud->dummy); - } - - SAVEDESTRUCTOR_X(reap_pop, ud); -} - -#endif /* REAP_H */ diff --git a/t/50-external.t b/t/50-external.t index 2476cd6..e9c828b 100644 --- a/t/50-external.t +++ b/t/50-external.t @@ -3,7 +3,9 @@ use strict; use warnings; -use Test::More tests => 4; +use Config; + +use Test::More tests => 6; use lib 't/lib'; use VPIT::TestHelpers; @@ -40,3 +42,23 @@ SKIP: my $status = run_perl 'no indirect hook => sub { }; exit 0; package; new X;'; is $status, 0, 'indirect does not croak while package empty is in use'; } + +my $fork_status; +if ($Config::Config{d_fork} or $Config::Config{d_pseudofork}) { + $fork_status = run_perl 'my $pid = fork; exit 1 unless defined $pid; if ($pid) { waitpid $pid, 0; my $status = $?; exit(($status >> 8) || $status) } else { exit 0 }'; +} + +SKIP: +{ + my $tests = 2; + skip 'fork() or pseudo-forks are required to check END blocks in subprocesses' + => $tests unless defined $fork_status; + skip "Could not even fork a simple process (sample returned $fork_status)" + => $tests unless $fork_status == 0; + + my $status = run_perl 'require indirect; END { eval q[1] } my $pid = fork; exit 0 unless defined $pid; if ($pid) { waitpid $pid, 0; my $status = $?; exit(($status >> 8) || $status) } else { exit 0 }'; + is $status, 0, 'indirect and global END blocks executed at the end of a forked process (RT #99083)'; + + $status = run_perl 'require indirect; my $pid = fork; exit 0 unless defined $pid; if ($pid) { waitpid $pid, 0; my $status = $?; exit(($status >> 8) || $status) } else { eval q[END { eval q(1) }]; exit 0 }'; + is $status, 0, 'indirect and local END blocks executed at the end of a forked process'; +}