Re: Signal to a sleeping Perl program
by davido (Cardinal) on Jan 17, 2020 at 16:04 UTC
|
Does this need to remain resident and sleeping, or could it just be a cron that kicks off at 15 minute intervals? On Windows you could hand it to the task scheduler.
This still has the issue of how to stop it running; it's inconvenient to always be manipulating crontabs or task scheduler entities. But if the script started out like this:
__PACKAGE__->run(@ARGV)
if -e '/path/to/run-me.flag' && ! caller;
sub run {
# ... the work goes here...
}
...you would prevent future runs from doing anything. This doesn't address an stopping an in-progress run, but I think you are probably trying to prevent the script from waking up again. With this approach you just touch a file into existence if you want the script to proceed when the cron picks it up again. If the file has been removed the script won't proceed. You wouldn't want to leave an impotent cron laying around forever but if it's just a matter of needing to prevent it running for a few hours or days once in awhile, this seems like a reasonable solution.
| [reply] [d/l] |
Re: Signal to a sleeping Perl program
by choroba (Cardinal) on Jan 17, 2020 at 14:33 UTC
|
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
local $SIG{USR1} = sub {
say STDERR "Signal 1 caught.";
alarm 0;
};
local $SIG{USR2} = sub {
say STDERR "Bye!";
exit
};
my $sum = 0;
while (1) {
$sum += $_ for 1 .. 100;
say $sum;
say STDERR scalar localtime, " Sleeping...";
sleep 10;
say STDERR scalar localtime, " Ready!";
}
A sample session:
▏~ $ 11111522.pl &
[1] 28265
5050
Fri Jan 17 15:28:04 2020 Sleeping...
Fri Jan 17 15:28:14 2020 Ready!
10100
Fri Jan 17 15:28:14 2020 Sleeping...
▏~ $ kill -USR1 28265
Signal 1 caught.
Fri Jan 17 15:28:17 2020 Ready!
15150
Fri Jan 17 15:28:17 2020 Sleeping...
▏~ $ kill -USR2 28265
Bye!
[1]+ Done 11111522.pl
▏~ $
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
Re: Signal to a sleeping Perl program
by afoken (Chancellor) on Jan 17, 2020 at 15:36 UTC
|
I have [a] [...] script that [...] sleeps [...] If I add an ALRM signal handler, the ALRM stops working
One problem is in the man page sleep(3), at least on Linux:
Bugs
sleep() may be implemented using SIGALRM; mixing calls to alarm(2) and sleep() is a bad idea.
Using longjmp(3) from a signal handler or modifying the handling of SIGALRM while sleeping will cause undefined results.
program keeps running!!!! Any thoughts?
Multiple exclamation marks ...
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
Re: Signal to a sleeping Perl program
by LanX (Saint) on Jan 17, 2020 at 15:14 UTC
|
| [reply] [d/l] |
Re: Signal to a sleeping Perl program
by soonix (Canon) on Jan 17, 2020 at 19:39 UTC
|
I had the opposite idea of davido's: if you loop with a sleep, you could extend the loop condition like this:
while (! -e '/predefined/location/time_is_up') {
do {'your thing'};
sleep 900;
}
or, in appropriate places exit if -e '/predefined/location/time_is_up';
This would cause the script to end if you create that file. | [reply] [d/l] [select] |
Re: Signal to a sleeping Perl program
by talexb (Chancellor) on Jan 17, 2020 at 14:48 UTC
|
One way would be to break up the 15 minute sleep into smaller mini-sleeps. Presumably, waking up would allow your script to respond to the request to terminate.
Alex / talexb / Toronto
Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.
| [reply] [d/l] |
|
One way would be to break up the 15 minute sleep into smaller mini-sleeps. Presumably, waking up would allow your script to respond to the request to terminate.
Any signal, or at least any non-ignored signal interrupts sleep. No need for polling. See also sleep:
Causes the script to sleep for (integer) EXPR seconds, or forever if no argument is given. Returns the integer number of seconds actually slept.
May be interrupted if the process receives a signal [...]
Note: sleep() returns how long it actually slept, so your program can continue sleeping for the remaining time if some signal happened in between.
The C API sleep() behaves similar, see sleep(3), but it returns the remaining sleep time, not the time actually slept.
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] |
|
sub my_sleep {
my $sleep_time = (shift or 1); # total time to sleep
my $sleep_interval = (shift or 10); # wake up at least this often
my $start = time;
$stop_time = $start + $sleep_time;
while (time < $stop_time) {
sleep $sleep_time;
# handle wake up tasks
}
my $elapsed = time - $start;
return $elapsed; # total time actually slept (plus shipping and ha
+ndling)
}
You may want additional conditions, and use this as a timeout mechanism. There's probably a nice module for that, or roll your own.
But the point is sleep comes with an unspoken if (...), if something else doesn't wake me up.
-QM
--
Quantum Mechanics: The dreams stuff is made of
| [reply] [d/l] [select] |
Re: Signal to a sleeping Perl program
by ikegami (Patriarch) on Jan 20, 2020 at 15:56 UTC
|
Handled signals causes blocking system calls to be interrupted (so the signal can be handled). You need to handle those errors.
sub uninterruptible_sleep {
my $sleep_until = time() + $_[0];
while (1) {
my $time_left = $sleep_until - time();
return if $time_left <= 0;
sleep($time_left);
}
}
| [reply] [d/l] |
Re: Signal to a sleeping Perl program
by jerryhone (Sexton) on Jan 19, 2020 at 23:38 UTC
|
Thanks everyone for responses. The OS I'm actually working on is Solaris, and I've had various thoughts about how to forcefully break into the loop, but the consensus here seems to be that the signal handler should work - it just doesn't! | [reply] |
|
#!/usr/bin/perl
use strict; # https://perlmonks.org/?node_id=11111522
use warnings; # borrowed from choroba
use feature qw{ say };
local $SIG{USR1} = sub
{
say STDERR "Signal 1 caught.";
};
local $SIG{USR2} = sub
{
say STDERR "Bye!";
exit
};
my $sum = 0;
while (1)
{
$sum += $_ for 1 .. 100;
say $sum;
say STDERR scalar localtime, " Sleeping...";
select undef, undef, undef, 10;
say STDERR scalar localtime, " Ready!";
}
I don't have a Solaris to test on, but this works as expected on my linux system.
| [reply] [d/l] |
|
Maybe you should have replied earlier, most of us thought you are on Windows.
| [reply] |
Re: Signal to a sleeping Perl program
by Anonymous Monk on Jan 20, 2020 at 15:43 UTC
|
I've got the signal handler operational, but I'm still a little puzzled by what was going on...only discovered by dropping deep into the debugger!
What I thought was the process hitting the sleep was actually the process disappearing into an Oracle DBI call and not coming out as there was a format conversion error in the SQL . DBI didn't return an error - it just hung and was uninterruptible, and I'm now guessing that the Oracle DBD module was resetting the signal handlers so my signals were ignored. Either way, correcting the SQL has resulted in a process that not only runs and produces required outcome but stops when asked!
| [reply] |
|
So it's solved! Thanks for the info!
The thread is long, this info might get overlooked.
It would have been nice tho if the OP used a SSCCE from the start and responded quicker.
UPDATED
redacted snarky remark.
| [reply] |