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