Skip to content

Commit

Permalink
Merge pull request #743 from kevin-bates/prefer-process-groups
Browse files Browse the repository at this point in the history
  • Loading branch information
blink1073 authored Feb 3, 2022
2 parents fc9b688 + db2d7c8 commit 10decd2
Showing 1 changed file with 38 additions and 18 deletions.
56 changes: 38 additions & 18 deletions jupyter_client/provisioning/local_provisioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,34 +85,54 @@ async def send_signal(self, signum: int) -> None:
os.killpg(self.pgid, signum)
return
except OSError:
pass
try:
self.process.send_signal(signum)
except OSError:
pass
pass # We'll retry sending the signal to only the process below

# If we're here, send the signal to the process and let caller handle exceptions
self.process.send_signal(signum)
return

async def kill(self, restart: bool = False) -> None:
if self.process:
if hasattr(signal, "SIGKILL"):
# If available, give preference to signalling the process-group over `kill()`.
try:
await self.send_signal(signal.SIGKILL)
return
except OSError:
pass
try:
self.process.kill()
except OSError as e:
# In Windows, we will get an Access Denied error if the process
# has already terminated. Ignore it.
if sys.platform == 'win32':
if e.winerror != 5:
raise
# On Unix, we may get an ESRCH error if the process has already
# terminated. Ignore it.
else:
from errno import ESRCH

if e.errno != ESRCH:
raise
LocalProvisioner._tolerate_no_process(e)

async def terminate(self, restart: bool = False) -> None:
if self.process:
return self.process.terminate()
if hasattr(signal, "SIGTERM"):
# If available, give preference to signalling the process group over `terminate()`.
try:
await self.send_signal(signal.SIGTERM)
return
except OSError:
pass
try:
self.process.terminate()
except OSError as e:
LocalProvisioner._tolerate_no_process(e)

@staticmethod
def _tolerate_no_process(os_error: OSError):
# In Windows, we will get an Access Denied error if the process
# has already terminated. Ignore it.
if sys.platform == 'win32':
if os_error.winerror != 5:
raise
# On Unix, we may get an ESRCH error (or ProcessLookupError instance) if
# the process has already terminated. Ignore it.
else:
from errno import ESRCH

if not isinstance(os_error, ProcessLookupError) or os_error.errno != ESRCH:
raise

async def cleanup(self, restart: bool = False) -> None:
if self.ports_cached and not restart:
Expand Down

0 comments on commit 10decd2

Please sign in to comment.