Allow program to have many (10 max in this example) independent alarms for time intervals >= 0.01 sec.
These alarms don't conflict with standart alarm(). Standart sleep() will be canceled when one of alarm's signal arrives.
Each alarm require 1 file descriptor, 1 signal handler between SIG50..59 and 1 forked process taking no CPU time, only memory.
Realization of cron-like system based on one such alarm and realization of sleep() which will not cancel when signal arrives left as exercise for reader. :-)
# just "macro" function from our library
sub Cat {
local *F;
open F, "< ".$_[0] or return;
local $/ unless wantarray;
return <F>;
}
{
my $SYS_setitimer = ( join("", map { Cat("/usr/include/$_.h") }
qw(syscall sys/syscall bits/syscall asm/unistd) ) =~
/^\s*#define\s*(?:__NR|SYS)_setitimer\s*(\d+)/m )[0];
my %ALARM = ();
# $n = alarm_start(0.01, \$counter) or die;
# $n = alarm_start(2.50, \&handler) or die;
# alarm_stop($n);
sub alarm_start {
my ($PARENT, $time, $counter) = ($$, @_);
return unless my ($n) = grep { not exists $ALARM{$_} } 50..59;
@{$ALARM{$n}}{"sec","usec"} =
(int($time), int(($time-int($time))*1000000));
$SIG{"NUM".$n} = ref($counter) eq "SCALAR" ? sub {$$counter++} :
$counter;
pipe $ALARM{$n}{READ}, $ALARM{$n}{WRITE};
if (!fork()) {
$0 .= " ALARM $n";
close $ALARM{$n}{WRITE};
$SIG{ALRM} = sub { kill $n, $PARENT };
# FIXME 0 mean ITIMER_REAL from <sys/time.h>
syscall $SYS_setitimer, 0, pack("llll",
(@{$ALARM{$n}}{"sec","usec"})x2), "\x00"x16;
read $ALARM{$n}{READ}, my $buf, 1;
print "Chield $n died\n";
exit;
}
close $ALARM{$n}{READ};
return $n;
}
sub alarm_stop {
$SIG{"NUM".$_[0]} = "IGNORE";
print {$ALARM{$_[0]}{WRITE}} "\n" if exists $ALARM{$_[0]};
delete $ALARM{$_[0]};
}
}
# Example:
$n1 = alarm_start(0.001, \$c1) or die 1;
$n2 = alarm_start(0.01, \$c2) or die 2;
$n3 = alarm_start(0.1, \$c3) or die 3;
$n4 = alarm_start(1, \$c4) or die 4;
$n5 = alarm_start(1.5, \$c5) or die 5;
$n6 = alarm_start(0.02, sub { $c6++ }) or die 6;
$t0 = time();
$i++ while time()<$t0+10;
print "Parent died: i=$i c1=$c1 c2=$c2 c3=$c3 c4=$c4 c5=$c5 c6=$c6\n";