Add shutdownModule function
Add and call shutdownModule function, in order to allow modules to clean up. use shutdownModule instead of shutdown to avoid confusion with severs/dispatchers shutdown and to make it consistent with initModule etc. Try to resolve module dependencies Change-Id: I2a091bf74ecadc2395fcdf92c599f1c49eb120f5 Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31339 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
This commit is contained in:
@ -639,6 +639,13 @@ class Module(HasAccessibles):
|
||||
all parameters are polled once
|
||||
"""
|
||||
|
||||
def shutdownModule(self):
|
||||
"""called when the sever shuts down
|
||||
|
||||
any cleanup-work should be performed here, like closing threads and
|
||||
saving data.
|
||||
"""
|
||||
|
||||
def doPoll(self):
|
||||
"""polls important parameters like value and status
|
||||
|
||||
|
@ -159,6 +159,8 @@ class Server:
|
||||
systemd.daemon.notify("READY=1\nSTATUS=accepting requests")
|
||||
self.interface.serve_forever()
|
||||
self.interface.server_close()
|
||||
for name in self._getSortedModules():
|
||||
self.modules[name].shutdownModule()
|
||||
if self._restart:
|
||||
self.restart_hook()
|
||||
self.log.info('restart')
|
||||
@ -300,3 +302,41 @@ class Server:
|
||||
# history_path = os.environ.get('ALTERNATIVE_HISTORY')
|
||||
# if history_path:
|
||||
# from frappy_<xx>.historywriter import ... etc.
|
||||
|
||||
def _getSortedModules(self):
|
||||
"""Sort modules topologically by inverse dependency.
|
||||
|
||||
Example: if there is an IO device A and module B depends on it, then
|
||||
the result will be [B, A].
|
||||
Right now, if the dependency graph is not a DAG, we give up and return
|
||||
the unvisited nodes to be dismantled at the end.
|
||||
Taken from Introduction to Algorithms [CLRS].
|
||||
"""
|
||||
def go(name):
|
||||
if name in done: # visiting a node
|
||||
return True
|
||||
if name in visited:
|
||||
visited.add(name)
|
||||
return False # cycle in dependencies -> fail
|
||||
visited.add(name)
|
||||
if name in unmarked:
|
||||
unmarked.remove(name)
|
||||
for module in self.modules[name].attachedModules.values():
|
||||
res = go(module.name)
|
||||
if not res:
|
||||
return False
|
||||
visited.remove(name)
|
||||
done.add(name)
|
||||
l.append(name)
|
||||
return True
|
||||
|
||||
unmarked = set(self.modules.keys()) # unvisited nodes
|
||||
visited = set() # visited in DFS, but not completed
|
||||
done = set()
|
||||
l = [] # list of sorted modules
|
||||
|
||||
while unmarked:
|
||||
if not go(unmarked.pop()):
|
||||
self.log.error('cyclical dependency between modules!')
|
||||
return l[::-1] + list(visited) + list(unmarked)
|
||||
return l[::-1]
|
||||
|
@ -354,7 +354,7 @@ class Cryostat(CryoBase):
|
||||
timestamp = t
|
||||
self.read_value()
|
||||
|
||||
def shutdown(self):
|
||||
def shutdownModule(self):
|
||||
# should be called from server when the server is stopped
|
||||
self._stopflag = True
|
||||
if self._thread and self._thread.is_alive():
|
||||
|
Reference in New Issue
Block a user