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