De-retardize XS-less behavior under SpeedyCGI
[p5sagit/Devel-GlobalDestruction.git] / lib / Devel / GlobalDestruction.pm
CommitLineData
a91e8a78 1package Devel::GlobalDestruction;
2
3use strict;
4use warnings;
5
989c3c9a 6our $VERSION = '0.05';
a91e8a78 7
a91e8a78 8use Sub::Exporter -setup => {
f832e240 9 exports => [ qw(in_global_destruction) ],
10 groups => { default => [ -all ] },
a91e8a78 11};
12
eaac10b5 13if (defined ${^GLOBAL_PHASE}) {
3790e928 14 eval 'sub in_global_destruction () { ${^GLOBAL_PHASE} eq q[DESTRUCT] }';
15}
9aaf3646 16elsif (eval {
17 require XSLoader;
3790e928 18 XSLoader::load(__PACKAGE__, $VERSION);
9aaf3646 19 1;
20}) {
21 # the eval already installed everything, nothing to do
3790e928 22}
9aaf3646 23else {
9d5ad143 24
25 # SpeedyCGI runs END blocks every cycle but somehow keeps object instances
26 # hence DIAF
27 die("The pure-perl version of @{[__PACKAGE__]} can not function correctly under CGI::SpeedyCGI. "
28 . "Please ensure you have a working compiler, and reinstall @{[__PACKAGE__]} to enable the XS "
29 . "codepath.\n"
30 ) if $CGI::SpeedyCGI::i_am_speedy;
31
9aaf3646 32 eval <<'PP_IGD' or die $@;
3790e928 33
9aaf3646 34my ($in_global_destruction, $before_is_installed);
a91e8a78 35
9aaf3646 36sub in_global_destruction { $in_global_destruction }
37
38END {
9d5ad143 39 $in_global_destruction = 1;
9aaf3646 40}
41
42# threads do not execute the global ENDs (it would be stupid). However
43# one can register a new END via simple string eval within a thread, and
44# achieve the same result. A logical place to do this would be CLONE, which
45# is claimed to run in the context of the new thread. However this does
46# not really seem to be the case - any END evaled in a CLONE is ignored :(
47# Hence blatantly hooking threads::create
48
49if ($INC{'threads.pm'}) {
50 my $orig_create = threads->can('create');
51 no warnings 'redefine';
52 *threads::create = sub {
53 { local $@; eval 'END { $in_global_destruction = 1 }' };
54 goto $orig_create;
55 };
56 $before_is_installed = 1;
57}
58
59# just in case threads got loaded after us (silly)
60sub CLONE {
61 unless ($before_is_installed) {
62 require Carp;
63 Carp::croak("You must load the 'threads' module before @{[ __PACKAGE__ ]}");
64 }
65}
a91e8a78 66
9aaf3646 671; # keep eval happy
68
69PP_IGD
70
71}
72
731; # keep require happy
74
75
76__END__
a91e8a78 77
78=head1 NAME
79
761f3ee2 80Devel::GlobalDestruction - Expose the flag which marks global
a91e8a78 81destruction.
82
83=head1 SYNOPSIS
84
f832e240 85 package Foo;
86 use Devel::GlobalDestruction;
a91e8a78 87
f832e240 88 use namespace::clean; # to avoid having an "in_global_destruction" method
a91e8a78 89
f832e240 90 sub DESTROY {
91 return if in_global_destruction;
a91e8a78 92
f832e240 93 do_something_a_little_tricky();
94 }
a91e8a78 95
96=head1 DESCRIPTION
97
98Perl's global destruction is a little tricky to deal with WRT finalizers
99because it's not ordered and objects can sometimes disappear.
100
101Writing defensive destructors is hard and annoying, and usually if global
102destruction is happenning you only need the destructors that free up non
103process local resources to actually execute.
104
105For these constructors you can avoid the mess by simply bailing out if global
106destruction is in effect.
107
108=head1 EXPORTS
109
110This module uses L<Sub::Exporter> so the exports may be renamed, aliased, etc.
111
112=over 4
113
114=item in_global_destruction
115
761f3ee2 116Returns true if the interpreter is in global destruction. In perl 5.14+, this
117returns C<${^GLOBAL_PHASE} eq 'DESTRUCT'>, and on earlier perls, it returns the
118current value of C<PL_dirty>.
a91e8a78 119
120=back
121
ec94b9e1 122=head1 AUTHORS
a91e8a78 123
124Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt>
125
ec94b9e1 126Florian Ragwitz E<lt>rafl@debian.orgE<gt>
127
aaa7f60f 128Jesse Luehrs E<lt>doy@tozt.netE<gt>
129
9aaf3646 130Peter Rabbitson E<lt>ribasushi@cpan.orgE<gt>
131
a91e8a78 132=head1 COPYRIGHT
133
f832e240 134 Copyright (c) 2008 Yuval Kogman. All rights reserved
135 This program is free software; you can redistribute
136 it and/or modify it under the same terms as Perl itself.
a91e8a78 137
138=cut