]> git.vpit.fr Git - perl/modules/autovivification.git/commitdiff
When a thread exits, teardown what we set up
authorVincent Pit <vince@profvince.com>
Sat, 24 Apr 2010 15:07:23 +0000 (17:07 +0200)
committerVincent Pit <vince@profvince.com>
Sat, 24 Apr 2010 15:09:26 +0000 (17:09 +0200)
MANIFEST
autovivification.xs
t/51-threads-teardown.t [new file with mode: 0644]

index 1feb9c4b12ba2c3ea5ad0366df84073a926047ef..0658bcd4a8af861ac2e59772fd5618771303bfd7 100644 (file)
--- 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
index b4c76a1cb02c5ee8961394aaf027d290499a2029..aa9011abaf7a65809c2dc886997095eefe4573a2 100644 (file)
@@ -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 (file)
index 0000000..d769fb6
--- /dev/null
@@ -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';
+}