Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

218 lines (165 sloc) 5.809 kB
# The data necessary to manage tagged extra/external reference counts
# on sessions, and the accessors to get at them sanely from other
# files.
package POE::Resource::Extrefs;
use vars qw($VERSION);
$VERSION = '1.350'; # NOTE - Should be #.### (three decimal places)
# These methods are folded into POE::Kernel;
package POE::Kernel;
use strict;
### The count of all extra references used in the system.
my %kr_extra_refs;
# ( $session_id =>
# { $tag => $count,
# ...,
# },
# ...,
# );
sub _data_extref_relocate_kernel_id {
my ($self, $old_id, $new_id) = @_;
return unless exists $kr_extra_refs{$old_id};
$kr_extra_refs{$new_id} = delete $kr_extra_refs{$old_id};
}
### End-run leak checking.
sub _data_extref_finalize {
my $finalized_ok = 1;
foreach my $session_id (keys %kr_extra_refs) {
$finalized_ok = 0;
_warn "!!! Leaked extref: $session_id\n";
foreach my $tag (keys %{$kr_extra_refs{$session_id}}) {
_warn "!!!\t`$tag' = $kr_extra_refs{$session_id}->{$tag}\n";
}
}
return $finalized_ok;
}
# Increment a session's tagged reference count. If this is the first
# time the tag is used in the session, then increment the session's
# reference count as well. Returns the tag's new reference count.
#
# TODO Allows incrementing reference counts on sessions that don't
# exist, but the public interface catches that.
#
# TODO Need to track extref ownership for signal-based session
# termination. One problem seen is that signals terminate sessions
# out of order. Owners think extra refcounts exist for sessions that
# are no longer around. Ownership trees give us a few benefits: We
# can make sure sessions destruct in a cleaner order. We can detect
# refcount loops and possibly prevent that.
sub _data_extref_inc {
my ($self, $sid, $tag) = @_;
my $refcount = ++$kr_extra_refs{$sid}->{$tag};
# TODO We could probably get away with only incrementing the
# session's master refcount once, as long as any extra refcount is
# positive. Then the session reference count would be a flag
# instead of a counter.
$self->_data_ses_refcount_inc($sid) if $refcount == 1;
if (TRACE_REFCNT) {
_warn(
"<rc> incremented extref ``$tag'' (now $refcount) for ",
$self->_data_alias_loggable($sid)
);
}
return $refcount;
}
# Decrement a session's tagged reference count, removing it outright
# if the count reaches zero. Return the new reference count or undef
# if the tag doesn't exist.
#
# TODO Allows negative reference counts, and the resulting hilarity.
# Hopefully the public interface won't allow it.
sub _data_extref_dec {
my ($self, $sid, $tag) = @_;
if (ASSERT_DATA) {
# Prevents autoviv.
_trap("<dt> decrementing extref for session without any")
unless exists $kr_extra_refs{$sid};
unless (exists $kr_extra_refs{$sid}->{$tag}) {
_trap(
"<dt> decrementing extref for nonexistent tag ``$tag'' in ",
$self->_data_alias_loggable($sid)
);
}
}
my $refcount = --$kr_extra_refs{$sid}->{$tag};
if (TRACE_REFCNT) {
_warn(
"<rc> decremented extref ``$tag'' (now $refcount) for ",
$self->_data_alias_loggable($sid)
);
}
$self->_data_extref_remove($sid, $tag) unless $refcount;
return $refcount;
}
### Remove an extra reference from a session, regardless of its count.
sub _data_extref_remove {
my ($self, $sid, $tag) = @_;
if (ASSERT_DATA) {
# Prevents autoviv.
_trap("<dt> removing extref from session without any")
unless exists $kr_extra_refs{$sid};
unless (exists $kr_extra_refs{$sid}->{$tag}) {
_trap(
"<dt> removing extref for nonexistent tag ``$tag'' in ",
$self->_data_alias_loggable($sid)
);
}
}
delete $kr_extra_refs{$sid}->{$tag};
delete $kr_extra_refs{$sid} unless scalar keys %{$kr_extra_refs{$sid}};
$self->_data_ses_refcount_dec($sid);
}
### Clear all the extra references from a session.
sub _data_extref_clear_session {
my ($self, $sid) = @_;
# TODO - Should there be a _trap here if the session doesn't exist?
return unless exists $kr_extra_refs{$sid}; # avoid autoviv
foreach (keys %{$kr_extra_refs{$sid}}) {
$self->_data_extref_remove($sid, $_);
}
if (ASSERT_DATA) {
if (exists $kr_extra_refs{$sid}) {
_trap(
"<dt> extref clear did not remove session ",
$self->_data_alias_loggable($sid)
);
}
}
}
# Fetch the number of sessions with extra references held in the
# entire system.
sub _data_extref_count {
return scalar keys %kr_extra_refs;
}
# Fetch whether a session has extra references.
sub _data_extref_count_ses {
my ($self, $sid) = @_;
return 0 unless exists $kr_extra_refs{$sid};
return scalar keys %{$kr_extra_refs{$sid}};
}
1;
__END__
=head1 NAME
POE::Resource::Extrefs - internal reference counts manager for POE::Kernel
=head1 SYNOPSIS
There is no public API.
=head1 DESCRIPTION
POE::Resource::Extrefs is a mix-in class for POE::Kernel. It provides
the features to manage session reference counts, specifically the ones
that applications may use. POE::Resource::Extrefs is used internally
by POE::Kernel, so it has no public interface.
=head1 SEE ALSO
See L<POE::Kernel/Public Reference Counters> for the public extref
API.
See L<POE::Kernel/Resources> for for public information about POE
resources.
See L<POE::Resource> for general discussion about resources and the
classes that manage them.
=head1 BUGS
Reference counters have no ownership information, so one entity's
reference counts may conflict with another's. This is usually not a
problem if all entities behave.
=head1 AUTHORS & COPYRIGHTS
Please see L<POE> for more information about authors and contributors.
=cut
# rocco // vim: ts=2 sw=2 expandtab
# TODO - Edit.
Jump to Line
Something went wrong with that request. Please try again.