Async-Event-Interval
view release on metacpan or search on metacpan
lib/Async/Event/Interval.pm view on Meta::CPAN
}
# Phase 2: Kill children (bounded by poll loops, no alarm needed).
for my $pid (@pids) {
kill 'TERM', $pid;
}
for my $pid (@pids) {
for (1..10) {
last unless kill(0, $pid);
select(undef, undef, undef, 0.05);
}
kill 'KILL', $pid if kill(0, $pid);
}
# Phase 3: Clear %events (1 second timeout).
_alarmed_eval(1, sub {
_events_write(sub {
delete @events{keys %events};
});
});
# Phase 4: Release IPC segments (1 second timeout).
#
# IPC::Shareable's STORE on a nested hashref/arrayref creates child
# segments and calls _remove_child() on the previous value. When a forked
# child does that during its callback, the parent's global_register still
# lists the now-dead child segments. clean_up_protected then re-removes
# them and shmctl() returns EINVAL. The cleanup itself is correct (seg
# count returns to baseline); only the warning is spurious, so filter it.
_alarmed_eval(1, sub {
local $SIG{__WARN__} = sub {
my $msg = shift;
return if $msg =~ /Couldn't remove (?:shm segment|semaphore set) \d+: Invalid argument/;
return if $msg =~ /Use of uninitialized value \$sem_remove_status/;
return if $msg =~ /Use of uninitialized value \$id in hash element/;
warn $msg;
};
IPC::Shareable::clean_up_protected(_shm_lock());
});
}
sub DESTROY {
my $self = $_[0];
return if $$ != $creator_pid;
return if $_shutting_down;
if (defined $self) {
$self->stop if $self->pid;
}
# On events with interval of zero, ForkManager runs finish(), which calls
# our destroy method. We only want to blow away the %events hash if we truly
# go out of scope
return if (caller())[0] eq 'Parallel::ForkManager::Child';
# Release any shared_scalar segments owned by this event. These are tracked
# in $self->{_shared_scalars}, not inside %events, so they can be cleaned up
# outside the %events lock.
if ($self->{_shared_scalars}) {
for my $scalar (@{ $self->{_shared_scalars} }) {
next unless ref $scalar eq 'SCALAR';
my $knot = tied $$scalar;
eval { $knot->remove } if $knot;
}
}
my $ok = eval {
_events_write(sub {
delete $events{$self->id};
$events{_event_count}--;
});
1;
};
if (! $ok) {
if (my $knot = tied(%events)) {
$knot->{_lock} = 0;
}
}
}
END {
_end(1);
}
sub _vim{} # vim navigation marker; intentionally empty
1;
__END__
=head1 NAME
Async::Event::Interval - Scheduled and one-off restartable asynchronous events
=for html
<a href="https://github.com/stevieb9/async-event-interval/actions"><img src="https://github.com/stevieb9/async-event-interval/workflows/CI/badge.svg"/></a>
<a href='https://coveralls.io/github/stevieb9/async-event-interval?branch=master'><img src='https://coveralls.io/repos/stevieb9/async-event-interval/badge.svg?branch=master&service=github' alt='Coverage Status' /></a>
=head1 SYNOPSIS
Here's an example of a simple asynchronous event that fetches JSON data from a
website every two seconds using a shared scalar variable to hold the decoded
JSON hashref, while allowing the main application to continue running in the
foreground. Multiple events can be used simultaneously if desired.
See the L</SCENARIOS/EXAMPLES> section for further usage examples.
use warnings;
use strict;
use Async::Event::Interval;
use JSON;
( run in 0.746 second using v1.01-cache-2.11-cpan-817d5f8af8b )