From: Vincent Pit Date: Sat, 24 Apr 2010 15:07:23 +0000 (+0200) Subject: When a thread exits, teardown what we set up X-Git-Tag: v0.06~2 X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2Fautovivification.git;a=commitdiff_plain;h=2639ec27efc735d677fde3aa5dd0588531d88245 When a thread exits, teardown what we set up --- diff --git a/MANIFEST b/MANIFEST index 1feb9c4..0658bcd 100644 --- a/MANIFEST +++ b/MANIFEST @@ -18,6 +18,7 @@ t/33-array-tied.t t/40-scope.t t/41-padsv.t t/42-deparse.t +t/51-threads-teardown.t t/91-pod.t t/92-pod-coverage.t t/95-portability-files.t diff --git a/autovivification.xs b/autovivification.xs index b4c76a1..aa9011a 100644 --- a/autovivification.xs +++ b/autovivification.xs @@ -973,6 +973,117 @@ STATIC OP *a_ck_root(pTHX_ OP *o) { 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 @@ -981,13 +1092,8 @@ PROTOTYPES: ENABLE 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 @@ -996,37 +1102,6 @@ BOOT: 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)); @@ -1038,6 +1113,8 @@ BOOT: newCONSTSUB(stash, "A_THREADSAFE", newSVuv(A_THREADSAFE)); newCONSTSUB(stash, "A_FORKSAFE", newSVuv(A_FORKSAFE)); } + + a_setup(); } #if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION diff --git a/t/51-threads-teardown.t b/t/51-threads-teardown.t new file mode 100644 index 0000000..d769fb6 --- /dev/null +++ b/t/51-threads-teardown.t @@ -0,0 +1,57 @@ +#!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'; +}