Skip to content

Commit

Permalink
Merge pull request #20562 from impact27/wait_all_shutdown
Browse files Browse the repository at this point in the history
PR: Wait on all shutdown threads (IPython console)
  • Loading branch information
ccordoba12 authored Feb 19, 2023
2 parents 6154bc7 + aa9ff17 commit 6996fb8
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 26 deletions.
9 changes: 2 additions & 7 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,6 @@ def test_leaks(main_window, qtbot):
Many other ways of leaking exist but are not covered here.
"""
def wait_all_shutdown():
objects = gc.get_objects()
for o in objects:
if isinstance(o, KernelHandler):
o.wait_shutdown_thread()

def ns_fun(main_window, qtbot):
# Wait until the window is fully up
Expand All @@ -148,7 +143,7 @@ def ns_fun(main_window, qtbot):
# Count initial objects
# Only one of each should be present, but because of many leaks,
# this is most likely not the case. Here only closing is tested
wait_all_shutdown()
KernelHandler.wait_all_shutdown_threads()
gc.collect()
objects = gc.get_objects()
n_code_editor_init = 0
Expand Down Expand Up @@ -183,7 +178,7 @@ def ns_fun(main_window, qtbot):
main_window.ipyconsole.restart()

# Wait until the shells are closed
wait_all_shutdown()
KernelHandler.wait_all_shutdown_threads()
return n_shell_init, n_code_editor_init

n_shell_init, n_code_editor_init = ns_fun(main_window, qtbot)
Expand Down
37 changes: 22 additions & 15 deletions spyder/plugins/ipythonconsole/utils/kernel_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ class KernelHandler(QObject):
The kernel raised an error while connecting.
"""

_shutdown_thread_list = []
"""List of running shutdown threads"""

_shutdown_thread_list_lock = Lock()
"""
Lock to add threads to _shutdown_thread_list or clear that list.
"""

def __init__(
self,
connection_file,
Expand Down Expand Up @@ -165,7 +173,6 @@ def __init__(
self.handle_comm_ready)

# Internal
self._shutdown_thread = None
self._shutdown_lock = Lock()
self._stdout_thread = None
self._stderr_thread = None
Expand Down Expand Up @@ -489,7 +496,6 @@ def init_kernel_client(cls, connection_file, hostname, sshkey, password):
def close(self, shutdown_kernel=True, now=False):
"""Close kernel"""
self.close_comm()

if shutdown_kernel and self.kernel_manager is not None:
km = self.kernel_manager
km.stop_restarter()
Expand All @@ -503,7 +509,8 @@ def close(self, shutdown_kernel=True, now=False):
shutdown_thread.run = self._thread_shutdown_kernel
shutdown_thread.start()
shutdown_thread.finished.connect(self.after_shutdown)
self._shutdown_thread = shutdown_thread
with self._shutdown_thread_list_lock:
self._shutdown_thread_list.append(shutdown_thread)

if (
self.kernel_client is not None
Expand All @@ -515,7 +522,6 @@ def after_shutdown(self):
"""Cleanup after shutdown"""
self.close_std_threads()
self.kernel_comm.remove(only_closing=True)
self._shutdown_thread = None

def _thread_shutdown_kernel(self):
"""Shutdown kernel."""
Expand All @@ -531,18 +537,19 @@ def _thread_shutdown_kernel(self):
# kernel was externally killed
pass

def wait_shutdown_thread(self):
@classmethod
def wait_all_shutdown_threads(cls):
"""Wait shutdown thread."""
thread = self._shutdown_thread
if thread is None:
return
if thread.isRunning():
try:
thread.kernel_manager._kill_kernel()
except Exception:
pass
thread.quit()
thread.wait()
with cls._shutdown_thread_list_lock:
for thread in cls._shutdown_thread_list:
if thread.isRunning():
try:
thread.kernel_manager._kill_kernel()
except Exception:
pass
thread.quit()
thread.wait()
cls._shutdown_thread_list = []

def copy(self):
"""Copy kernel."""
Expand Down
6 changes: 2 additions & 4 deletions spyder/plugins/ipythonconsole/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -1644,10 +1644,8 @@ def close_all_clients(self):
client.close_client(is_last_client)
open_clients.remove(client)

# Wait for all KernelHandler's to shutdown.
for client in self.clients:
if client.kernel_handler:
client.kernel_handler.wait_shutdown_thread()
# Wait for all KernelHandler threads to shutdown.
KernelHandler.wait_all_shutdown_threads()

# Close cached kernel
self.close_cached_kernel()
Expand Down

0 comments on commit 6996fb8

Please sign in to comment.