Count and track the main threads, so we can delay disconnecting until all have quit.
This commit is contained in:
parent
8ee30179ea
commit
913738444e
@ -282,6 +282,8 @@ class XMLStream(object):
|
|||||||
self.__event_handlers = {}
|
self.__event_handlers = {}
|
||||||
self.__event_handlers_lock = threading.Lock()
|
self.__event_handlers_lock = threading.Lock()
|
||||||
self.__filters = {'in': [], 'out': [], 'out_sync': []}
|
self.__filters = {'in': [], 'out': [], 'out_sync': []}
|
||||||
|
self.__thread_count = 0
|
||||||
|
self.__thread_cond = threading.Condition()
|
||||||
self._use_daemons = False
|
self._use_daemons = False
|
||||||
|
|
||||||
self._id = 0
|
self._id = 0
|
||||||
@ -650,6 +652,8 @@ class XMLStream(object):
|
|||||||
|
|
||||||
if not self.auto_reconnect:
|
if not self.auto_reconnect:
|
||||||
self.stop.set()
|
self.stop.set()
|
||||||
|
self._wait_for_threads()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.socket.shutdown(Socket.SHUT_RDWR)
|
self.socket.shutdown(Socket.SHUT_RDWR)
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
@ -1174,6 +1178,26 @@ class XMLStream(object):
|
|||||||
self.send_queue.put(data)
|
self.send_queue.put(data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _start_thread(self, name, target, track=True):
|
||||||
|
self.__thread[name] = threading.Thread(name=name, target=target)
|
||||||
|
self.__thread[name].daemon = self._use_daemons
|
||||||
|
self.__thread[name].start()
|
||||||
|
|
||||||
|
with self.__thread_cond:
|
||||||
|
self.__thread_count += 1
|
||||||
|
|
||||||
|
def _end_thread(self, name):
|
||||||
|
with self.__thread_cond:
|
||||||
|
self.__thread_count -= 1
|
||||||
|
log.debug("Stopped %s thread. %s threads remain." % (
|
||||||
|
name, self.__thread_count))
|
||||||
|
if self.__thread_count == 0:
|
||||||
|
self.__thread_cond.notify()
|
||||||
|
|
||||||
|
def _wait_for_threads(self):
|
||||||
|
with self.__thread_cond:
|
||||||
|
self.__thread_cond.wait()
|
||||||
|
|
||||||
def process(self, **kwargs):
|
def process(self, **kwargs):
|
||||||
"""Initialize the XML streams and begin processing events.
|
"""Initialize the XML streams and begin processing events.
|
||||||
|
|
||||||
@ -1207,22 +1231,16 @@ class XMLStream(object):
|
|||||||
else:
|
else:
|
||||||
threaded = kwargs.get('threaded', True)
|
threaded = kwargs.get('threaded', True)
|
||||||
|
|
||||||
self.scheduler.process(threaded=True, daemon=self._use_daemons)
|
|
||||||
|
|
||||||
def start_thread(name, target):
|
|
||||||
self.__thread[name] = threading.Thread(name=name, target=target)
|
|
||||||
self.__thread[name].daemon = self._use_daemons
|
|
||||||
self.__thread[name].start()
|
|
||||||
|
|
||||||
for t in range(0, HANDLER_THREADS):
|
for t in range(0, HANDLER_THREADS):
|
||||||
log.debug("Starting HANDLER THREAD")
|
log.debug("Starting HANDLER THREAD")
|
||||||
start_thread('stream_event_handler_%s' % t, self._event_runner)
|
self._start_thread('event_thread_%s' % t, self._event_runner)
|
||||||
|
|
||||||
start_thread('send_thread', self._send_thread)
|
self._start_thread('send_thread', self._send_thread)
|
||||||
|
self._start_thread('scheduler_thread', self._scheduler_thread)
|
||||||
|
|
||||||
if threaded:
|
if threaded:
|
||||||
# Run the XML stream in the background for another application.
|
# Run the XML stream in the background for another application.
|
||||||
start_thread('process', self._process)
|
self._start_thread('read_thread', self._process, track=False)
|
||||||
else:
|
else:
|
||||||
self._process()
|
self._process()
|
||||||
|
|
||||||
@ -1466,16 +1484,16 @@ class XMLStream(object):
|
|||||||
self.exception(e)
|
self.exception(e)
|
||||||
elif etype == 'quit':
|
elif etype == 'quit':
|
||||||
log.debug("Quitting event runner thread")
|
log.debug("Quitting event runner thread")
|
||||||
return False
|
break
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
log.debug("Keyboard Escape Detected in _event_runner")
|
log.debug("Keyboard Escape Detected in _event_runner")
|
||||||
self.event('killed', direct=True)
|
self.event('killed', direct=True)
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
return
|
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
self.event_queue.put(('quit', None, None))
|
self.event_queue.put(('quit', None, None))
|
||||||
return
|
|
||||||
|
self._end_thread('event runner')
|
||||||
|
|
||||||
def _send_thread(self):
|
def _send_thread(self):
|
||||||
"""Extract stanzas from the send queue and send them on the stream."""
|
"""Extract stanzas from the send queue and send them on the stream."""
|
||||||
@ -1530,6 +1548,12 @@ class XMLStream(object):
|
|||||||
if not self.stop.is_set():
|
if not self.stop.is_set():
|
||||||
self.disconnect(self.auto_reconnect)
|
self.disconnect(self.auto_reconnect)
|
||||||
|
|
||||||
|
self._end_thread('send')
|
||||||
|
|
||||||
|
def _scheduler_thread(self):
|
||||||
|
self.scheduler.process(threaded=False)
|
||||||
|
self._end_thread('scheduler')
|
||||||
|
|
||||||
def exception(self, exception):
|
def exception(self, exception):
|
||||||
"""Process an unknown exception.
|
"""Process an unknown exception.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user