From 6ac5044d2aabe09c08140852b4e45f0726eccade Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Mon, 14 Jan 2019 10:04:43 +0000
Subject: [PATCH] fhem.pl: add DelayedShutdownFn (Forum #95819)
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@18249 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
docs/commandref_frame.html | 7 ++++
docs/commandref_frame_DE.html | 7 ++++
fhem.pl | 63 +++++++++++++++++++++++++++++------
3 files changed, 67 insertions(+), 10 deletions(-)
diff --git a/docs/commandref_frame.html b/docs/commandref_frame.html
index 6e77ffbae..50f9cffba 100644
--- a/docs/commandref_frame.html
+++ b/docs/commandref_frame.html
@@ -1540,6 +1540,13 @@ The following local attributes are used by a wider range of devices:
{ $currlogfile }
.
+
+
FHEM
. The path
diff --git a/docs/commandref_frame_DE.html b/docs/commandref_frame_DE.html
index 7aa2afc59..96e938af9 100644
--- a/docs/commandref_frame_DE.html
+++ b/docs/commandref_frame_DE.html
@@ -1642,6 +1642,13 @@ Die folgenden lokalen Attribute werden von mehreren Geräten verwendet:
mit { $currlogfile }festlegen
.
FHEM
diff --git a/fhem.pl b/fhem.pl
index 854f9ba42..6bd857c97 100755
--- a/fhem.pl
+++ b/fhem.pl
@@ -180,7 +180,7 @@ sub CommandSave($$);
sub CommandSet($$);
sub CommandSetReading($$);
sub CommandSetstate($$);
-sub CommandShutdown($$);
+sub CommandShutdown($$;$$);
sub CommandSleep($$);
sub CommandTrigger($$);
@@ -209,9 +209,10 @@ sub cfgDB_WriteFile($@);
# ParseFn - Interpret a raw message
# ReadFn - Reading from a Device (see FHZ/WS300)
# ReadyFn - check for available data, if no FD
-# RenameFn - inform the device about its renameing
+# RenameFn - inform the device about its renaming
# SetFn - set/activate this device
-# ShutdownFn-called before shutdown
+# DelayedShutdownFn - used to delay shutdown for some seconds
+# ShutdownFn-called before shutdown, if DelayedShutdownFn is "over"
# StateFn - set local info for this device, do not activate anything
# UndefFn - clean up (delete timer, close fd), called by delete and rereadcfg
@@ -227,21 +228,25 @@ sub cfgDB_WriteFile($@);
# VOLATILE- Set if the definition should be saved to the "statefile"
# NOTIFYDEV - if set, the notifyFn will only be called for this device
+use vars qw($addTimerStacktrace);# set to 1 by fhemdebug
use vars qw($auth_refresh);
use vars qw($cmdFromAnalyze); # used by the warnings-sub
-use vars qw($lastWarningMsg); # set by the warnings-sub
use vars qw($cvsid); # used in 98_version.pm
use vars qw($devcount); # Maximum device number, used for storing
use vars qw($featurelevel);
+use vars qw($fhemForked); # 1 in a fhemFork()'ed process, else undef
use vars qw($fhem_started); # used for uptime calculation
+use vars qw($haveInet6); # Using INET6
use vars qw($init_done); #
use vars qw($internal_data); # FileLog/DbLog -> SVG data transport
use vars qw($lastDefChange); # number of last def/attr change
+use vars qw($lastWarningMsg); # set by the warnings-sub
use vars qw($nextat); # Time when next timer will be triggered.
use vars qw($readytimeout); # Polling interval. UNIX: device search only
use vars qw($reread_active);
use vars qw($selectTimestamp); # used to check last select exit timestamp
use vars qw($winService); # the Windows Service object
+
use vars qw(%attr); # Attributes
use vars qw(%cmds); # Global command name hash.
use vars qw(%data); # Hash for user data
@@ -249,21 +254,20 @@ use vars qw(%defaultattr); # Default attributes, used by FHEM2FHEM
use vars qw(%defs); # FHEM device/button definitions
use vars qw(%inform); # Used by telnet_ActivateInform
use vars qw(%intAt); # Internal timer hash, used by apptime
-use vars qw(@intAtA); # Internal timer array
use vars qw(%logInform); # Used by FHEMWEB/Event-Monitor
use vars qw(%modules); # List of loaded modules (device/log/etc)
use vars qw(%ntfyHash); # hash of devices needed to be notified.
use vars qw(%oldvalue); # Old values, see commandref.html
+use vars qw(%prioQueues); #
use vars qw(%readyfnlist); # devices which want a "readyfn"
use vars qw(%selectlist); # devices which want a "select"
use vars qw(%value); # Current values, see commandref.html
+
use vars qw(@authenticate); # List of authentication devices
use vars qw(@authorize); # List of authorization devices
+use vars qw(@intAtA); # Internal timer array
use vars qw(@structChangeHist); # Contains the last 10 structural changes
-use vars qw($haveInet6); # Using INET6
-use vars qw(%prioQueues); #
-use vars qw($fhemForked); # 1 in a fhemFork()'ed process, else undef
-use vars qw($addTimerStacktrace);# set to 1 by fhemdebug
+
$selectTimestamp = gettimeofday();
$cvsid = '$Id$';
@@ -287,6 +291,7 @@ my %comments; # Comments from the include files
my %duplicate; # Pool of received msg for multi-fhz/cul setups
my @cmdList; # Remaining commands in a chain. Used by sleep
my %sleepers; # list of sleepers
+my %delayedShutdowns; # definitions needing delayed shutdown
$init_done = 0;
$lastDefChange = 0;
@@ -328,6 +333,7 @@ my @globalAttrList = qw(
logdir
logfile
longitude
+ maxShutdownDelay
modpath
motd
mseclog:1,0
@@ -1703,9 +1709,45 @@ CommandSave($$)
#####################################
sub
-CommandShutdown($$)
+CancelDelayedShutdown($)
+{
+ my ($d) = @_;
+ delete($delayedShutdowns{$d});
+}
+
+sub
+DelayedShutdown($$)
{
my ($cl, $param) = @_;
+
+ %delayedShutdowns = ();
+ foreach my $d (sort keys %defs) {
+ $delayedShutdowns{$d} = 1 if(CallFn($d, "DelayedShutdownFn", $defs{$d}));
+ }
+ return 0 if(!keys %delayedShutdowns);
+
+ my $waitingFor = 0;
+ my $maxShutdownDelay = AttrVal("global", "maxShutdownDelay", 10);
+ my $checkList;
+
+ Log 1, "Server shutdown delayed due to ".join(",", keys %delayedShutdowns).
+ " for max $maxShutdownDelay sec";
+ DoTrigger("global", "DELAYEDSHUTDOWN", 1);
+
+ $checkList = sub()
+ {
+ return CommandShutdown($cl, $param, undef, 1)
+ if(!keys %delayedShutdowns || $waitingFor++ >= $maxShutdownDelay);
+ InternalTimer(gettimeofday()+1, $checkList, undef, 0);
+ };
+ $checkList->();
+ return 1;
+}
+
+sub
+CommandShutdown($$;$$)
+{
+ my ($cl, $param, $cmdName, $final) = @_;
my $exitValue = 0;
if($param && $param =~ m/^(\d+)$/) {
$exitValue = $1;
@@ -1713,6 +1755,7 @@ CommandShutdown($$)
}
return "Usage: shutdown [restart|exitvalue]"
if($param && $param ne "restart");
+ return if(!$final && DelayedShutdown($cl, $param));
DoTrigger("global", "SHUTDOWN", 1);
Log 0, "Server shutdown";