Skip to content

Commit

Permalink
esky.sudo: monitor helper process to avoid deadlock if it dies
Browse files Browse the repository at this point in the history
  • Loading branch information
rfk committed Sep 5, 2011
1 parent 25f2000 commit 3bd459b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
1 change: 1 addition & 0 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ v0.9.5
* Clean up handling of unbuffered mode in py2exe. (The old code
never actually worked; the new code works most of the time but
might give you the wrong mode if running from a partial update)
* esky.sudo: avoid deadlocking if the helper process dies.


v0.9.4
Expand Down
35 changes: 34 additions & 1 deletion esky/sudo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from __future__ import absolute_import

import sys
import time

from esky.util import lazy_import

Expand All @@ -48,6 +49,14 @@ def pickle():
import pickle
return pickle

@lazy_import
def threading():
try:
import threading
except ImportError:
threading = None
return threading


if sys.platform == "win32":
@lazy_import
Expand Down Expand Up @@ -114,9 +123,33 @@ def start(self):
(self.proc,self.pipe) = spawn_sudo(self)
if self.proc.poll() is not None:
raise RuntimeError("sudo helper process terminated unexpectedly")
if self.pipe.read() != b("READY"):
# If threading is available, run a background thread to monitor
# the sudo process. If it dies, terminate things immediately.
if threading:
self._do_monitor_proc = True
monitor_thread = threading.Thread(target=self._monitor_proc)
monitor_thread.daemon = True
monitor_thread.start()
# Try to read initialisation message from the pipe.
# If this fails, the helper program must have died.
try:
msg = self.pipe.read()
except EOFError:
msg = b("")
if msg != b("READY"):
self.close()
raise RuntimeError("failed to spawn helper app")
if threading:
self._do_monitor_proc = False
monitor_thread.join()

def _monitor_proc(self):
while self._do_monitor_proc:
if self.proc.poll() is not None:
self.pipe._recover()
self.pipe.close()
break
time.sleep(0)

def close(self):
self.pipe.write(b("CLOSE"))
Expand Down
2 changes: 1 addition & 1 deletion esky/sudo/sudo_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def check_connection(self):
self.connected = True

def close(self):
pass
self.connected = False

def read(self):
"""Read the next string from the pipe.
Expand Down

0 comments on commit 3bd459b

Please sign in to comment.