# SYNOPSYS # # # start new alarm (fork new process) # $alarm_id = alarm_start(0.01, \$counter); # # # stop alarm (kill forked process) # alarm_stop($alarm_id); # # # sleep without been interrupted by signals # sleepy(0.5); # # # limit CPU usage to 10% # Limit_CPU(); # use Time::HiRes qw(time alarm setitimer ITIMER_PROF); { my %ALARM; sub alarm_start { my ($PARENT, $time, $counter) = ($$, @_); return unless $time > 0; return unless my ($n) = grep { not exists $ALARM{$_} } "NUM50" .. "NUM59"; $SIG{$n} = ref($counter) eq "SCALAR" ? sub { $$counter++ } : ref($counter) eq "CODE" ? sub { local $SIG{$n}="IGNORE"; &$counter } : return; return $n if $ALARM{$n} = fork(); $0 .= " ALARM $n"; $SIG{ALRM} = sub { kill $n, $PARENT or exit }; alarm($time, $time); CORE::sleep 1 while 1; } sub alarm_stop { return unless exists $ALARM{$_[0]}; local $SIG{CHLD} = $SIG{$_[0]} = "IGNORE"; kill 9, $ALARM{$_[0]} and waitpid delete $ALARM{$_[0]}, 0; }} sub sleepy { my $alarm = alarm_start($_[0], \(my $wakeup)) or die "sleepy: alarm failed"; # die or return? CORE::sleep 1 until $wakeup; alarm_stop($alarm); } use constant CPUMAX => 10; # percent, max CPU load by this process use constant INT => 0.1; # sec, how often check for CPU overload { my ($real, $prof, $wait); $SIG{PROF} = sub { $prof++ }; sub Limit_CPU { setitimer(ITIMER_PROF, INT, INT); alarm_start(INT, sub { $wait = ($prof*(100/CPUMAX) - ++$real) / (1/INT); return if INT > $wait; sleepy($wait); $real += int( $wait * (1/INT) ); }); }}