alarmをネストする方法

だいたいこんな感じ。結局使わないコードだけど。alarm(0) を呼んでからセットしてるのは、$SIG{ALRM} の差し替え中にシグナルが飛んでくる可能性を考えて。このあたりは自分がセットするシグナルハンドラの仕様によっては、高速化の余地があるはず。

sub create_nested_alarm_guard {
    my $old_alarm_after = Time::HiRes::alarm(0);
    my $old_alarm_at =
        $old_alarm_after ? Time::HiRes::time + $old_alarm_after : 0;
    my $old_alarm_handler = $SIG{ALRM};
    Scope::Guard->new(sub {
        my $now = Time::HiRes::time;
        Time::HiRes::ualarm(0);
        $SIG{ALRM} = $old_alarm_handler;
        if ($old_alarm_at != 0) {
            Time::HiRes::ualarm(
                $now < $old_alarm_at ? ($old_alarm_at - $now) * 1000000: 1)
        }
    });
};

sub doit {
    my $guard = create_nested_alarm_guard();
    $SIG{ALRM} = sub { ... };
    alarm($timeout);
    ...
}