Terminate processes when the pipes are broken, or the queues are raising exceptions. Helps with cleaning up orphaned processes when the software crashes.
This commit is contained in:
parent
6f782f237e
commit
921c1b067f
@ -231,7 +231,12 @@ class AvStreamProcess(mp.Process):
|
|||||||
self.siggen_activated = Atomic(False)
|
self.siggen_activated = Atomic(False)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
msg, data = self.pipe.recv()
|
try:
|
||||||
|
msg, data = self.pipe.recv()
|
||||||
|
except OSError:
|
||||||
|
logging.error("Error with pipe, terminating process")
|
||||||
|
self.stopAllStreams()
|
||||||
|
self.terminate()
|
||||||
logging.debug(f"Streamprocess obtained message {msg}")
|
logging.debug(f"Streamprocess obtained message {msg}")
|
||||||
|
|
||||||
if msg == StreamMsg.activateSiggen:
|
if msg == StreamMsg.activateSiggen:
|
||||||
@ -419,18 +424,28 @@ class AvStreamProcess(mp.Process):
|
|||||||
# explanation.
|
# explanation.
|
||||||
def sendInQueues(self, msg, *data):
|
def sendInQueues(self, msg, *data):
|
||||||
# logging.debug('sendInQueues()')
|
# logging.debug('sendInQueues()')
|
||||||
for q in self.indata_qlist:
|
try:
|
||||||
# Fan out the input data to all queues in the queue list
|
for q in self.indata_qlist:
|
||||||
q.put((msg, data))
|
# Fan out the input data to all queues in the queue list
|
||||||
|
q.put((msg, data))
|
||||||
|
except ValueError:
|
||||||
|
logging.error("Error with data queue, terminating process")
|
||||||
|
self.stopAllStreams()
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
def sendAllQueues(self, msg, *data):
|
def sendAllQueues(self, msg, *data):
|
||||||
"""
|
"""
|
||||||
Destined for all queues, including capture data queues
|
Destined for all queues, including capture data queues
|
||||||
"""
|
"""
|
||||||
self.sendInQueues(msg, *data)
|
self.sendInQueues(msg, *data)
|
||||||
for q in self.msg_qlist:
|
try:
|
||||||
# Fan out the input data to all queues in the queue list
|
for q in self.msg_qlist:
|
||||||
q.put((msg, data))
|
# Fan out the input data to all queues in the queue list
|
||||||
|
q.put((msg, data))
|
||||||
|
except ValueError:
|
||||||
|
logging.error("Error with data queue, terminating process")
|
||||||
|
self.stopAllStreams()
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -181,7 +181,13 @@ class SiggenProcess(mp.Process):
|
|||||||
if np.issubdtype(dtype, np.integer):
|
if np.issubdtype(dtype, np.integer):
|
||||||
bitdepth_fixed = dtype.itemsize * 8
|
bitdepth_fixed = dtype.itemsize * 8
|
||||||
signal *= 2 ** (bitdepth_fixed - 1) - 1
|
signal *= 2 ** (bitdepth_fixed - 1) - 1
|
||||||
self.dataq.put(signal.astype(dtype))
|
try:
|
||||||
|
self.dataq.put(signal.astype(dtype))
|
||||||
|
except ValueError:
|
||||||
|
# As of Python 3.8, a value error on a Queue means that the oter
|
||||||
|
# end of the process died.
|
||||||
|
logging.error("Error with data queue, terminating process")
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
def newEqualizer(self, eqdata):
|
def newEqualizer(self, eqdata):
|
||||||
"""
|
"""
|
||||||
@ -207,6 +213,13 @@ class SiggenProcess(mp.Process):
|
|||||||
eq.setLevels(eq_levels)
|
eq.setLevels(eq_levels)
|
||||||
return eq
|
return eq
|
||||||
|
|
||||||
|
def sendPipe(self, msgtype, msg):
|
||||||
|
try:
|
||||||
|
self.pipe.send((msgtype, msg))
|
||||||
|
except OSError:
|
||||||
|
logging.error("Error with pipe, terminating process")
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# The main function of the actual process
|
# The main function of the actual process
|
||||||
# First things first
|
# First things first
|
||||||
@ -215,23 +228,28 @@ class SiggenProcess(mp.Process):
|
|||||||
try:
|
try:
|
||||||
self.siggen = self.newSiggen(self.siggendata)
|
self.siggen = self.newSiggen(self.siggendata)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.pipe.send((SiggenMessage.error, str(e)))
|
self.sendPipe(SiggenMessage.error, str(e))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.eq = self.newEqualizer(self.siggendata.eqdata)
|
self.eq = self.newEqualizer(self.siggendata.eqdata)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.pipe.send((SiggenMessage.error, str(e)))
|
self.sendPipe(SiggenMessage.error, str(e))
|
||||||
|
|
||||||
# Pre-generate blocks of signal data
|
# Pre-generate blocks of signal data
|
||||||
while self.dataq.qsize() < self.nblocks_buffer:
|
while self.dataq.qsize() < self.nblocks_buffer:
|
||||||
self.generate()
|
self.generate()
|
||||||
|
|
||||||
self.pipe.send((SiggenMessage.ready, None))
|
self.sendPipe(SiggenMessage.ready, None)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# Wait here for a while, to check for messages to consume
|
# Wait here for a while, to check for messages to consume
|
||||||
if self.pipe.poll(timeout=QUEUE_BUFFER_TIME / 4):
|
if self.pipe.poll(timeout=QUEUE_BUFFER_TIME / 4):
|
||||||
msg, data = self.pipe.recv()
|
try:
|
||||||
|
msg, data = self.pipe.recv()
|
||||||
|
except OSError:
|
||||||
|
logging.error("Error with pipe, terminating process")
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
if msg == SiggenMessage.endProcess:
|
if msg == SiggenMessage.endProcess:
|
||||||
logging.debug("Signal generator caught 'endProcess' message. Exiting.")
|
logging.debug("Signal generator caught 'endProcess' message. Exiting.")
|
||||||
return 0
|
return 0
|
||||||
@ -254,7 +272,7 @@ class SiggenProcess(mp.Process):
|
|||||||
try:
|
try:
|
||||||
self.generate()
|
self.generate()
|
||||||
except SiggenWorkerDone:
|
except SiggenWorkerDone:
|
||||||
self.pipe.send(SiggenMessage.done)
|
self.sendPipe(SiggenMessage.done, None)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
Loading…
Reference in New Issue
Block a user