STATIC U32 a_initialized = 0;
+STATIC void a_teardown(pTHX_ void *root) {
+
+ if (!a_initialized)
+ return;
+
+#if A_MULTIPLICITY
+ if (aTHX != root)
+ return;
+#endif
+
+#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
+ {
+ dMY_CXT;
+ ptable_hints_free(MY_CXT.tbl);
+ }
+#endif
+
+ PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_old_ck_padany);
+ a_old_ck_padany = 0;
+ PL_check[OP_PADSV] = MEMBER_TO_FPTR(a_old_ck_padsv);
+ a_old_ck_padsv = 0;
+
+ PL_check[OP_AELEM] = MEMBER_TO_FPTR(a_old_ck_aelem);
+ a_old_ck_aelem = 0;
+ PL_check[OP_HELEM] = MEMBER_TO_FPTR(a_old_ck_helem);
+ a_old_ck_helem = 0;
+ PL_check[OP_RV2SV] = MEMBER_TO_FPTR(a_old_ck_rv2sv);
+ a_old_ck_rv2sv = 0;
+
+ PL_check[OP_RV2AV] = MEMBER_TO_FPTR(a_old_ck_rv2av);
+ a_old_ck_rv2av = 0;
+ PL_check[OP_RV2HV] = MEMBER_TO_FPTR(a_old_ck_rv2hv);
+ a_old_ck_rv2hv = 0;
+
+ PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_old_ck_aslice);
+ a_old_ck_aslice = 0;
+ PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_old_ck_hslice);
+ a_old_ck_hslice = 0;
+
+ PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_old_ck_exists);
+ a_old_ck_exists = 0;
+ PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_old_ck_delete);
+ a_old_ck_delete = 0;
+ PL_check[OP_KEYS] = MEMBER_TO_FPTR(a_old_ck_keys);
+ a_old_ck_keys = 0;
+ PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_old_ck_values);
+ a_old_ck_values = 0;
+
+ if (a_pp_padsv_saved) {
+ PL_ppaddr[OP_PADSV] = a_pp_padsv_saved;
+ a_pp_padsv_saved = 0;
+ }
+
+ a_initialized = 0;
+}
+
+STATIC void a_setup(pTHX) {
+#define a_setup() a_setup(aTHX)
+ if (a_initialized)
+ return;
+
+#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
+ {
+ MY_CXT_INIT;
+ MY_CXT.tbl = ptable_new();
+ MY_CXT.owner = aTHX;
+ }
+#endif
+
+ a_old_ck_padany = PL_check[OP_PADANY];
+ PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_ck_padany);
+ a_old_ck_padsv = PL_check[OP_PADSV];
+ PL_check[OP_PADSV] = MEMBER_TO_FPTR(a_ck_padsv);
+
+ a_old_ck_aelem = PL_check[OP_AELEM];
+ PL_check[OP_AELEM] = MEMBER_TO_FPTR(a_ck_deref);
+ a_old_ck_helem = PL_check[OP_HELEM];
+ PL_check[OP_HELEM] = MEMBER_TO_FPTR(a_ck_deref);
+ a_old_ck_rv2sv = PL_check[OP_RV2SV];
+ PL_check[OP_RV2SV] = MEMBER_TO_FPTR(a_ck_deref);
+
+ a_old_ck_rv2av = PL_check[OP_RV2AV];
+ PL_check[OP_RV2AV] = MEMBER_TO_FPTR(a_ck_rv2xv);
+ a_old_ck_rv2hv = PL_check[OP_RV2HV];
+ PL_check[OP_RV2HV] = MEMBER_TO_FPTR(a_ck_rv2xv);
+
+ a_old_ck_aslice = PL_check[OP_ASLICE];
+ PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_ck_xslice);
+ a_old_ck_hslice = PL_check[OP_HSLICE];
+ PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_ck_xslice);
+
+ a_old_ck_exists = PL_check[OP_EXISTS];
+ PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
+ a_old_ck_delete = PL_check[OP_DELETE];
+ PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_ck_root);
+ a_old_ck_keys = PL_check[OP_KEYS];
+ PL_check[OP_KEYS] = MEMBER_TO_FPTR(a_ck_root);
+ a_old_ck_values = PL_check[OP_VALUES];
+ PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_ck_root);
+
+#if A_MULTIPLICITY
+ call_atexit(a_teardown, aTHX);
+#else
+ call_atexit(a_teardown, NULL);
+#endif
+
+ a_initialized = 1;
+}
+
+STATIC U32 a_booted = 0;
+
/* --- XS ------------------------------------------------------------------ */
MODULE = autovivification PACKAGE = autovivification
BOOT:
{
- if (!a_initialized++) {
+ if (!a_booted++) {
HV *stash;
-#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
- MY_CXT_INIT;
- MY_CXT.tbl = ptable_new();
- MY_CXT.owner = aTHX;
-#endif
a_op_map = ptable_new();
#ifdef USE_ITHREADS
PERL_HASH(a_hash, __PACKAGE__, __PACKAGE_LEN__);
- a_old_ck_padany = PL_check[OP_PADANY];
- PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_ck_padany);
- a_old_ck_padsv = PL_check[OP_PADSV];
- PL_check[OP_PADSV] = MEMBER_TO_FPTR(a_ck_padsv);
-
- a_old_ck_aelem = PL_check[OP_AELEM];
- PL_check[OP_AELEM] = MEMBER_TO_FPTR(a_ck_deref);
- a_old_ck_helem = PL_check[OP_HELEM];
- PL_check[OP_HELEM] = MEMBER_TO_FPTR(a_ck_deref);
- a_old_ck_rv2sv = PL_check[OP_RV2SV];
- PL_check[OP_RV2SV] = MEMBER_TO_FPTR(a_ck_deref);
-
- a_old_ck_rv2av = PL_check[OP_RV2AV];
- PL_check[OP_RV2AV] = MEMBER_TO_FPTR(a_ck_rv2xv);
- a_old_ck_rv2hv = PL_check[OP_RV2HV];
- PL_check[OP_RV2HV] = MEMBER_TO_FPTR(a_ck_rv2xv);
-
- a_old_ck_aslice = PL_check[OP_ASLICE];
- PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_ck_xslice);
- a_old_ck_hslice = PL_check[OP_HSLICE];
- PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_ck_xslice);
-
- a_old_ck_exists = PL_check[OP_EXISTS];
- PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
- a_old_ck_delete = PL_check[OP_DELETE];
- PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_ck_root);
- a_old_ck_keys = PL_check[OP_KEYS];
- PL_check[OP_KEYS] = MEMBER_TO_FPTR(a_ck_root);
- a_old_ck_values = PL_check[OP_VALUES];
- PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_ck_root);
-
stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT));
newCONSTSUB(stash, "A_HINT_WARN", newSVuv(A_HINT_WARN));
newCONSTSUB(stash, "A_THREADSAFE", newSVuv(A_THREADSAFE));
newCONSTSUB(stash, "A_FORKSAFE", newSVuv(A_FORKSAFE));
}
+
+ a_setup();
}
#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
--- /dev/null
+#!perl
+
+use strict;
+use warnings;
+
+use Config qw/%Config/;
+
+BEGIN {
+ if (!$Config{useithreads}) {
+ require Test::More;
+ Test::More->import;
+ plan(skip_all => 'This perl wasn\'t built to support threads');
+ }
+}
+
+use threads;
+
+use Test::More;
+
+BEGIN {
+ require autovivification;
+ if (autovivification::A_THREADSAFE()) {
+ plan tests => 1;
+ defined and diag "Using threads $_" for $threads::VERSION;
+ } else {
+ plan skip_all => 'This autovivification isn\'t thread safe';
+ }
+}
+
+sub run_perl {
+ my $code = shift;
+
+ my $SystemRoot = $ENV{SystemRoot};
+ local %ENV;
+ $ENV{SystemRoot} = $SystemRoot if $^O eq 'MSWin32' and defined $SystemRoot;
+
+ system { $^X } $^X, '-T', map("-I$_", @INC), '-e', $code;
+}
+
+SKIP:
+{
+ skip 'Fails on 5.8.2 and lower' => 1 if $] <= 5.008002;
+
+ my $status = run_perl <<' RUN';
+ my $code = 1 + 2 + 4;
+ use threads;
+ $code -= threads->create(sub {
+ eval q{no autovivification; my $x; my $y = $x->{foo}; $x};
+ return defined($x) ? 0 : 1;
+ })->join;
+ $code -= defined(eval q{my $x; my $y = $x->{foo}; $x}) ? 2 : 0;
+ $code -= defined(eval q{no autovivification; my $x; my $y = $x->{foo}; $x})
+ ? 0 : 4;
+ exit $code;
+ RUN
+ is $status, 0, 'loading the pragma in a thread and using it outside doesn\'t segfault';
+}