diff --git a/IPython/html/notebookapp.py b/IPython/html/notebookapp.py index 2dc404c..85bf440 100644 --- a/IPython/html/notebookapp.py +++ b/IPython/html/notebookapp.py @@ -74,6 +74,7 @@ from IPython.kernel.zmq.session import default_secure, Session from IPython.nbformat.sign import NotebookNotary from IPython.utils.importstring import import_item from IPython.utils import submodule +from IPython.utils.process import check_pid from IPython.utils.traitlets import ( Dict, Unicode, Integer, List, Bool, Bytes, Instance, DottedObjectName, TraitError, @@ -844,6 +845,7 @@ class NotebookApp(BaseIPythonApplication): 'secure': bool(self.certfile), 'base_url': self.base_url, 'notebook_dir': os.path.abspath(self.notebook_dir), + 'pid': os.getpid() } def write_server_info_file(self): @@ -917,8 +919,17 @@ def list_running_servers(profile='default'): for file in os.listdir(pd.security_dir): if file.startswith('nbserver-'): with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f: - yield json.load(f) + info = json.load(f) + # Simple check whether that process is really still running + if check_pid(info['pid']): + yield info + else: + # If the process has died, try to delete its info file + try: + os.unlink(file) + except OSError: + pass # TODO: This should warn or log or something #----------------------------------------------------------------------------- # Main entry point #----------------------------------------------------------------------------- diff --git a/IPython/utils/_process_posix.py b/IPython/utils/_process_posix.py index 9c6054f..07be022 100644 --- a/IPython/utils/_process_posix.py +++ b/IPython/utils/_process_posix.py @@ -16,6 +16,8 @@ This file is only meant to be imported by process.py, not by end-users. from __future__ import print_function # Stdlib +import errno +import os import subprocess as sp import sys @@ -209,5 +211,15 @@ class ProcessHandler(object): # (ls is a good example) that makes them hard. system = ProcessHandler().system - - +def check_pid(pid): + try: + os.kill(pid, 0) + except OSError as err: + if err.errno == errno.ESRCH: + return False + elif err.errno == errno.EPERM: + # Don't have permission to signal the process - probably means it exists + return True + raise + else: + return True diff --git a/IPython/utils/_process_win32.py b/IPython/utils/_process_win32.py index 8b30c23..3ac59b2 100644 --- a/IPython/utils/_process_win32.py +++ b/IPython/utils/_process_win32.py @@ -185,3 +185,8 @@ try: return result except AttributeError: arg_split = py_arg_split + +def check_pid(pid): + # OpenProcess returns 0 if no such process (of ours) exists + # positive int otherwise + return bool(ctypes.windll.kernel32.OpenProcess(1,0,pid)) diff --git a/IPython/utils/process.py b/IPython/utils/process.py index a7a54ea..2a19945 100644 --- a/IPython/utils/process.py +++ b/IPython/utils/process.py @@ -21,11 +21,11 @@ import sys # Our own if sys.platform == 'win32': - from ._process_win32 import _find_cmd, system, getoutput, arg_split + from ._process_win32 import _find_cmd, system, getoutput, arg_split, check_pid elif sys.platform == 'cli': from ._process_cli import _find_cmd, system, getoutput, arg_split else: - from ._process_posix import _find_cmd, system, getoutput, arg_split + from ._process_posix import _find_cmd, system, getoutput, arg_split, check_pid from ._process_common import getoutputerror, get_output_error_code, process_handler from . import py3compat