Reliably restarting "sleep"

Reliably restarting "sleep"

am 14.06.2011 09:23:27 von Peter Daum

Hi,

the subject is admittedly not very enlighening ... ;-;
what I am trying to do is:

- run a little program, that just sleeps for a given time
- when it receives a signal, restarts sleeping again for the
full time period until it receives another signal or the
timer elapses. In the latter case it should just exit.
Something like:

sub sleeper {
warn strftime("%H:%M:%S sleep $sleeptime\n", localtime);
$SIG{USR1}=\&sleeper;
sleep $sleeptime;
};

warn $$;
sleeper;

It sounds very simple, but I can't get it to work as intended.
I tryied it in numberless variations using sleep, Time::HiRes,
alaram/pause ... the actual result is always pretty much the same:

- When the program receives the 1st USR1 signal, it is interrupted
immediately and "sleeper" is called. The pending alarm is obviously
canceled and restarted as intended
- Any subsequent USR1 signal is only reacted to when the full $sleeptime
starting from the previous signal is elapsed. If more than 1 signal is
received in the meantime, additional signals are lost.

Does anybody have an idea why this doesn't work and how to get the
intendeded result? Any suggestions are appreciated ...
(This is taking place on a Linux 2.6.32 kernel using perl 5.10.0 ...)

Regards,
Peter


--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 14.06.2011 12:31:53 von Peter Daum

Hi,

On 2011-06-14 09:23, gator_ml@yahoo.de wrote:
> what I am trying to do is:
>
> - run a little program, that just sleeps for a given time
> - when it receives a signal, restarts sleeping again for the
> full time period until it receives another signal or the
> timer elapses. In the latter case it should just exit.
> Something like:
>
> sub sleeper {
> warn strftime("%H:%M:%S sleep $sleeptime\n", localtime);
> $SIG{USR1}=\&sleeper;
> sleep $sleeptime;
> };
>
> warn $$;
> sleeper;
>
> It sounds very simple, but I can't get it to work as intended.

.... meanwhile a found a solution; in case somebody with
the same problem stumbles upon this, here's what I came up with:

my $caught_signal=0;

sub expired {
warn strftime("%H:%M:%S expired\n", localtime);
exit 0;
}

sub sleeper {
warn strftime("%H:%M:%S sleep $sleeptime\n", localtime);
alarm $sleeptime; pause;
};

sub usr1 { alarm 0; $caught_signal=1; }

$SIG{USR1}=\&usr1;
$SIG{ALRM}=\&expired;
while(1) {
if($caught_signal) {
$caught_signal=0;
} else {
sleeper();
}
}

The problem obviously was, that I called "sleep" from within the
USR1 signal handler and (generally not a bad idea ;) this signal
had been blocked there.
If somebody knows a more elegant solution, let me know ...

Regards,
Peter


--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 15.06.2011 14:18:11 von derykus

On Jun 14, 3:31=A0am, gator...@yahoo.de wrote:
> Hi,
>
> On 2011-06-14 09:23, gator...@yahoo.de wrote:
>
>
>
>
>
>
>
>
>
> > what I am trying to do is:
>
> > - run a little program, that just sleeps for a given time
> > - when it receives a signal, restarts sleeping again for the
> > =A0 full time period until it receives another signal or the
> > =A0 timer elapses. In the latter case it should just exit.
> > =A0 Something like:
>
> > sub sleeper {
> > =A0 =A0 warn strftime("%H:%M:%S sleep $sleeptime\n", localtime);
> > =A0 =A0 $SIG{USR1}=3D\&sleeper;
> > =A0 =A0 sleep $sleeptime;
> > };
>
> > warn $$;
> > sleeper;
>
> > It sounds very simple, but I can't get it to work as intended.
>
> ... meanwhile a found a solution; in case somebody with
> the same problem stumbles upon this, here's what I came up with:
>
> my $caught_signal=3D0;
>
> sub expired {
> =A0 =A0 warn strftime("%H:%M:%S expired\n", localtime);
> =A0 =A0 exit 0;
>
> }
>
> sub sleeper {
> =A0 =A0 warn strftime("%H:%M:%S sleep $sleeptime\n", localtime);
> =A0 =A0 alarm $sleeptime; pause;
>
> };
>
> sub usr1 { alarm 0; $caught_signal=3D1; }
>
> $SIG{USR1}=3D\&usr1;
> $SIG{ALRM}=3D\&expired;
> while(1) {
> =A0 =A0 if($caught_signal) {
> =A0 =A0 =A0 =A0 $caught_signal=3D0;
> =A0 =A0 } else {
> =A0 =A0 =A0 =A0 sleeper();
> =A0 =A0 }
>
> }
>
> The problem obviously was, that I called "sleep" from within the
> USR1 signal handler and (generally not a bad idea ;) this signal
> had been blocked there.
> If somebody knows a more elegant solution, let me know ...
>

Not sure of your actual program detail but mixing
alarm/sleep is a bad idea. See: perldoc -f alarm.

Another solution, not necessarily more elegant, but
more familiar to most is an eval {} and alarm pair:

EVAL: {
eval {
local $SIG{ ALRM } =3D sub { die "alarm"; };
local $SIG{ USR1 } =3D sub { die "usr1" };
alarm $sleeptime;
... some long running operation here ....
alarm 0;
1;
} or do {
alarm 0;
if ( $@ =3D~ /alarm/) { warn "expired..." }
} elsif ( $@ =3D~ /usr1/) { redo EVAL; }
} elsif ($@) { die "unexpected error: $@"; }
}
}

--
Charles DeRykus


--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 16.06.2011 10:54:02 von rvtol+usenet

On 2011-06-15 14:18, C.DeRykus wrote:

> [...] mixing
> alarm/sleep is a bad idea. See: perldoc -f alarm.
>
> Another solution, not necessarily more elegant, but
> more familiar to most is an eval {} and alarm pair:
>
> EVAL: {
> eval {
> local $SIG{ ALRM } = sub { die "alarm"; };
> local $SIG{ USR1 } = sub { die "usr1" };
> alarm $sleeptime;
> ... some long running operation here ....
> alarm 0;
> 1;
> } or do {

Insert:
my $eval_error = $@ || "Zombie error!";

and use $eval_error in the code below.

> alarm 0;
> if ( $@ =~ /alarm/) { warn "expired..." }
> } elsif ( $@ =~ /usr1/) { redo EVAL; }
> } elsif ($@) { die "unexpected error: $@"; }
> }
> }


Realize that $@ is a global variable, so can get changed at a distance.

The last 'elsif' was particularly wrong: it would not die if $@ is
false. Just make it an 'else'.

--
Ruud

--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 16.06.2011 19:16:44 von derykus

On Jun 16, 1:54=A0am, rvtol+use...@isolution.nl ("Dr.Ruud") wrote:
> On 2011-06-15 14:18, C.DeRykus wrote:
>
> > [...] =A0mixing
> > alarm/sleep is a bad idea. See: perldoc -f alarm.
>
> > Another solution, not necessarily more elegant, but
> > more familiar to most =A0is an eval {} and alarm pair:
>
> > EVAL: {
> > =A0 =A0 =A0eval {
> > =A0 =A0 =A0 =A0 =A0 local $SIG{ ALRM } =3D sub { die "alarm"; };
> > =A0 =A0 =A0 =A0 =A0 local $SIG{ USR1 } =3D sub { die "usr1" };
> > =A0 =A0 =A0 =A0 =A0 alarm $sleeptime;
> > =A0 =A0 =A0 =A0 =A0 ... some long running operation here ....
> > =A0 =A0 =A0 =A0 =A0 alarm 0;
> > =A0 =A0 =A0 =A0 =A0 1;
> > =A0 =A0 =A0 } or do {
>
> Insert:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $eval_error =3D $@ || "Zombie error!";

Huh? If you insert that statement before doing 'alarm 0',
then, there's a potential have a race condition with the
alarm going off and terminating the entire program with
"alarm clock" before you can even check $@.


eval { ... ; "foo" happens and sets $@=3D'bar';
...
};
my $eval_error =3D $@ || "Zombie error!";
# alarm actually does go off now
# and terminates program
alarm 0; # too late
....
Therefore you wouldn't want to insert any statement
before turning off the alarm. Particularly if the
alarm handler is localized to the eval{} which is the
best idion.

>
> and use $eval_error in the code below.
>
> > =A0 =A0 =A0 =A0 =A0 =A0alarm 0;
> > =A0 =A0 =A0 =A0 =A0 =A0if ( $@ =3D~ /alarm/) =A0 =A0 { warn "expired...=
" }
> > =A0 =A0 =A0 =A0 =A0 =A0} elsif ( $@ =3D~ /usr1/) { redo EVAL; }
> > =A0 =A0 =A0 =A0 =A0 =A0} elsif ($@) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ di=
e "unexpected error: $@"; }
> > =A0 =A0 =A0 }
> > }
>
> Realize that $@ is a global variable, so can get changed at a distance.

Yes, but $@ was just set and the immediate danger is
an alarm race condition that needs to be addressed
first. The eval {} was just exited after all and nothing
intervenes except the $@ condition if-elsif clauses
that needed to protected from an uncaught alarm.

>
> The last 'elsif' was particularly wrong: it would not die if $@ is
> false. Just make it an 'else'.
>

But what kind of scenario would do that....? If there's
an uncaught signal for instance, the program will
still terminate immediately with an "alarm clock".
Or if the program unexpectedly exits in some benign
way inside the eval {}, you'd never see that final 'else'
clause anyway. If the final statement '1' in the eval {}
gets short-circuited somehow, I'd think all bets are off.

--
Charles DeRykus


--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 17.06.2011 00:00:56 von rvtol+usenet

On 2011-06-16 19:16, C.DeRykus wrote:
> Ruud:
>> C.DeRykus:

>>> Another solution, not necessarily more elegant, but
>>> more familiar to most is an eval {} and alarm pair:
>>
>>> EVAL: {
>>> eval {
>>> local $SIG{ ALRM } = sub { die "alarm"; };
>>> local $SIG{ USR1 } = sub { die "usr1" };
>>> alarm $sleeptime;
>>> ... some long running operation here ....
>>> alarm 0;
>>> 1;
>>> } or do {
>>
>> Insert:
>> my $eval_error = $@ || "Zombie error!";
>
> Huh? If you insert that statement before doing 'alarm 0',
> then, there's a potential have a race condition with the
> alarm going off and terminating the entire program with
> "alarm clock" before you can even check $@.

Realize that the alarm is then already reset (to the earlier setting)
because the localization gets out of scope.


> eval { ... ; "foo" happens and sets $@='bar';
> ...
> };
> my $eval_error = $@ || "Zombie error!";
> # alarm actually does go off now
> # and terminates program
> alarm 0; # too late
> ....
> Therefore you wouldn't want to insert any statement
> before turning off the alarm.

Because the alarm signal is localized (to the eval{}), it is not active
in the do{}.

To support 'nested' alarms (actually more 'in turns' than 'nested'), you
might want to do it like this:

EVAL: {
my $prev_timeout = alarm 0; # stop any outer alarm
my $timeout = 20;

eval {
my $alarm_on = 1;
local $SIG{ ALRM } = sub { die "evalarm" if $alarm_on };
local $SIG{ USR1 } = sub { $alarm_on = 0; die "usr1" };
alarm $timeout;

... some long running operation here (that might die itself) ...

$alarm_on = 0;
alarm $prev_timeout; # re-activate any outer alarm
1; # success
}
or do {
my $eval_error = $@ || "Zombie error!";
alarm $prev_timeout; # re-activate any outer alarm

if ( $eval_error =~ /evalarm/ ) { warn "expired..." }
elsif ( $eval_error =~ /usr1/ ) { redo EVAL }
else { die $eval_error }

};
}

--
Ruud

--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 17.06.2011 05:34:35 von derykus

On Jun 16, 3:00=A0pm, rvtol+use...@isolution.nl ("Dr.Ruud") wrote:
> On 2011-06-16 19:16, C.DeRykus wrote:
>
>
>
> > Ruud:
> >> C.DeRykus:
> >>> Another solution, not necessarily more elegant, but
> >>> more familiar to most =A0is an eval {} and alarm pair:
>
> >>> EVAL: {
> >>> =A0 =A0 =A0 eval {
> >>> =A0 =A0 =A0 =A0 =A0 =A0local $SIG{ ALRM } =3D sub { die "alarm"; };
> >>> =A0 =A0 =A0 =A0 =A0 =A0local $SIG{ USR1 } =3D sub { die "usr1" };
> >>> =A0 =A0 =A0 =A0 =A0 =A0alarm $sleeptime;
> >>> =A0 =A0 =A0 =A0 =A0 =A0... some long running operation here ....
> >>> =A0 =A0 =A0 =A0 =A0 =A0alarm 0;
> >>> =A0 =A0 =A0 =A0 =A0 =A01;
> >>> =A0 =A0 =A0 =A0} or do {
>
> >> Insert:
> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0my $eval_error =3D $@ || "Zombie error!=
";
>
> > Huh? =A0 If you insert that statement before doing 'alarm 0',
> > then, there's a potential have a race condition with the
> > alarm going off and terminating the entire program with
> > "alarm clock" before you can even check $@.
>
> Realize that the alarm is then already reset (to the earlier setting)
> because the localization gets out of scope.

No, that's not true. The localized signal handler gets
reset but any alarm that is started in that scope will
still be delivered to the current signal handler unless
turned off.

>
> > =A0 =A0 =A0 =A0 eval { =A0... =A0; "foo" happens and sets $@=3D'bar';
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ...
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0my $eval_error =3D $@ || "Zombie error!"=
;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 # =A0alarm actually does go=
off now
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 # =A0and terminates program
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0alarm 0; =A0 =A0 =A0# =A0too late
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0....
> > Therefore you wouldn't want to insert any statement
> > before turning off the alarm.
>
> Because the alarm signal is localized (to the eval{}), it is not active
> in the do{}.


No, it's still active. In the case below, the alarm
that was set inside the scope gets delivered to
the default alarm handler. On freebsd 8.2 for
instance:

$ perl -e 'eval{ local $SIG{ALRM}=3Dsub{die "foo"};
alarm 1}; <>'
Alarm clock: 14

So the alarm that was launched in the eval {} scope
is still active and, even though the localized handler
goes out of scope, the delivery still occurs later to
the default handler.

> ...

--
Charles DeRykus



--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 18.06.2011 15:50:35 von rvtol+usenet

On 2011-06-17 05:34, C.DeRykus wrote:
> Ruud:
>> C.DeRykus:
>>> Ruud:
>>>> C.DeRykus:

>>>>> Another solution, not necessarily more elegant, but
>>>>> more familiar to most is an eval {} and alarm pair:
>>
>>>>> EVAL: {
>>>>> eval {
>>>>> local $SIG{ ALRM } = sub { die "alarm"; };
>>>>> local $SIG{ USR1 } = sub { die "usr1" };
>>>>> alarm $sleeptime;
>>>>> ... some long running operation here ....
>>>>> alarm 0;
>>>>> 1;
>>>>> } or do {
>>
>>>> Insert:
>>>> my $eval_error = $@ || "Zombie error!";
>>
>>> Huh? If you insert that statement before doing 'alarm 0',
>>> then, there's a potential have a race condition with the
>>> alarm going off and terminating the entire program with
>>> "alarm clock" before you can even check $@.
>>
>> Realize that the alarm is then already reset (to the earlier setting)
>> because the localization gets out of scope.
>
> No, that's not true. The localized signal handler gets
> reset but any alarm that is started in that scope will
> still be delivered to the current signal handler unless
> turned off.

Right, but the word "alarm" in my sentence stood for "alarm signal
handler", so please re-read.


>>> eval { ... ; "foo" happens and sets $@='bar';
>>> ...
>>> };
>>> my $eval_error = $@ || "Zombie error!";
>>> # alarm actually does go off now
>>> # and terminates program
>>> alarm 0; # too late
>>> ....
>>> Therefore you wouldn't want to insert any statement
>>> before turning off the alarm.
>>
>> Because the alarm signal is localized (to the eval{}), it is not active
>> in the do{}.
>
> No, it's still active. In the case below, the alarm
> that was set inside the scope gets delivered to
> the default alarm handler.

And my "alarm signal" was short again for "alarm signal handler".


> On freebsd 8.2 for
> instance:
>
> $ perl -e 'eval{ local $SIG{ALRM}=sub{die "foo"};
> alarm 1};<>'
> Alarm clock: 14
>
> So the alarm that was launched in the eval {} scope
> is still active and, even though the localized handler
> goes out of scope, the delivery still occurs later to
> the default handler.

Well, I hope I cleared up my bad phrasing. Now best read it again.

--
Ruud

--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/

Re: Reliably restarting "sleep"

am 18.06.2011 19:17:04 von derykus

On Jun 18, 6:50=A0am, rvtol+use...@isolution.nl ("Dr.Ruud") wrote:
> On 2011-06-17 05:34, C.DeRykus wrote:
>
>
> > Ruud:
> >> C.DeRykus:
> >>> Ruud:
> >>>> C.DeRykus:
> >>>>> Another solution, not necessarily more elegant, but
> >>>>> more familiar to most =A0is an eval {} and alarm pair:
>
> >>>>> EVAL: {
> >>>>> =A0 =A0 =A0 =A0eval {
> >>>>> =A0 =A0 =A0 =A0 =A0 =A0 local $SIG{ ALRM } =3D sub { die "alarm"; }=
;
> >>>>> =A0 =A0 =A0 =A0 =A0 =A0 local $SIG{ USR1 } =3D sub { die "usr1" };
> >>>>> =A0 =A0 =A0 =A0 =A0 =A0 alarm $sleeptime;
> >>>>> =A0 =A0 =A0 =A0 =A0 =A0 ... some long running operation here ....
> >>>>> =A0 =A0 =A0 =A0 =A0 =A0 alarm 0;
> >>>>> =A0 =A0 =A0 =A0 =A0 =A0 1;
> >>>>> =A0 =A0 =A0 =A0 } or do {
>
> >>>> Insert:
> >>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $eval_error =3D $@ || "Zombie err=
or!";
>
> >>> Huh? =A0 If you insert that statement before doing 'alarm 0',
> >>> then, there's a potential have a race condition with the
> >>> alarm going off and terminating the entire program with
> >>> "alarm clock" before you can even check $@.
>
> >> Realize that the alarm is then already reset (to the earlier setting)
> >> because the localization gets out of scope.
>
> > No, that's not true. The localized signal handler gets
> > reset but =A0any alarm that is started in that scope will
> > still be delivered to the current signal handler unless
> > turned =A0off.
>
> Right, but the word "alarm" in my sentence stood for "alarm signal
> handler", so please re-read.
>
>

I'm sorry to have mis-read your response. With
just a signal name, I always tend to interpret it
narrowly as the signal itself and not the handler.


> >>> =A0 =A0 =A0 =A0 =A0eval { =A0... =A0; "foo" happens and sets $@=3D'ba=
r';
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0...
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $eval_error =3D $@ || "Zombie erro=
r!";
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0# =A0alarm actually do=
es go off now
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0# =A0and terminates pr=
ogram
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm 0; =A0 =A0 =A0# =A0too late
> >>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ....
> >>> Therefore you wouldn't want to insert any statement
> >>> before turning off the alarm.
>
> >> Because the alarm signal is localized (to the eval{}), it is not activ=
e
> >> in the do{}.
>
> > No, it's still active. In the case below, the alarm
> > that was set inside the scope gets delivered to
> > the default alarm handler.
>
> And my "alarm signal" was short again for "alarm signal handler".
>
> > On freebsd 8.2 for
> > instance:
>
> > $ perl -e 'eval{ local $SIG{ALRM}=3Dsub{die "foo"};
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm 1};<>'
> > Alarm clock: 14
>
> > So the alarm that was launched in the eval {} scope
> > is still active and, even though the localized handler
> > goes out of scope, =A0the delivery still occurs later to
> > the default handler.
>
> Well, I hope I cleared up my bad phrasing.

Should have been clear to me in that context
what you were referring to. Turning off the
undelivered alarm is good practice but I'll
re-read the whole thread.

--
Charles DeRykus



..


--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/