1 # This is just a concept-test. If works as intended will ship in its own
2 # right as Devel::GlobalDestruction::PP or perhaps even as part of rafls
5 package # hide from pause
6 DBIx::Class::GlobalDestruction;
12 our @EXPORT = 'in_global_destruction';
14 use DBIx::Class::Exception;
16 if (defined ${^GLOBAL_PHASE}) {
17 eval 'sub in_global_destruction () { ${^GLOBAL_PHASE} eq q[DESTRUCT] }';
19 elsif (eval { require Devel::GlobalDestruction }) { # use the XS version if available
20 *in_global_destruction = \&Devel::GlobalDestruction::in_global_destruction;
23 my ($in_global_destruction, $before_is_installed);
27 sub in_global_destruction () { $in_global_destruction }
30 # SpeedyCGI runs END blocks every cycle but keeps object instances
31 # hence we have to disable the globaldestroy hatch, and rely on the
32 # eval traps (which appears to work, but are risky done so late)
33 $in_global_destruction = 1 unless $CGI::SpeedyCGI::i_am_speedy;
36 # threads do not execute the global ENDs (it would be stupid). However
37 # one can register a new END via simple string eval within a thread, and
38 # achieve the same result. A logical place to do this would be CLONE, which
39 # is claimed to run in the context of the new thread. However this does
40 # not really seem to be the case - any END evaled in a CLONE is ignored :(
41 # Hence blatantly hooking threads::create
42 if ($INC{'threads.pm'}) {
43 require Class::Method::Modifiers;
44 Class::Method::Modifiers::install_modifier( threads => before => create => sub {
45 my $orig_target_cref = $_[1];
47 { local $@; eval 'END { $in_global_destruction = 1 }' }
48 $orig_target_cref->();
51 $before_is_installed = 1;
54 # just in case threads got loaded after DBIC (silly)
56 DBIx::Class::Exception->throw("You must load the 'threads' module before @{[ __PACKAGE__ ]}")
57 unless $before_is_installed;