[tor-commits] [chutney/master] Check RunAsDaemon before using wait()
nickm at torproject.org
nickm at torproject.org
Wed Oct 8 19:54:44 UTC 2014
commit f34ac80509272296c25de03c71763c995b1f7eb6
Author: teor <teor2345 at gmail.com>
Date: Thu Oct 2 01:58:00 2014 +1000
Check RunAsDaemon before using wait()
Avoid hangs by checking for RunAsDaemon 1 in the torrc before using
wait() on a launched tor process. Iff it's absent, use poll().
A configurable poll() time is provided in env['poll_launch_time'],
and a default in env['poll_launch_time_default'] is used when the torrc
is unexpectedly missing RunAsDaemon 1.
(TODO: We may only need one of these?)
---
lib/chutney/TorNet.py | 83 ++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 75 insertions(+), 8 deletions(-)
diff --git a/lib/chutney/TorNet.py b/lib/chutney/TorNet.py
index e4ddc7a..87f1abe 100644
--- a/lib/chutney/TorNet.py
+++ b/lib/chutney/TorNet.py
@@ -556,12 +556,35 @@ class LocalNodeController(NodeController):
sys.exit(0)
else:
raise
- # XXXX this requires that RunAsDaemon is set.
- p.wait()
- if p.returncode != 0:
- print "Couldn't launch %s (%s): %s" % (self._env['nick'],
- " ".join(cmdline),
- p.returncode)
+ if self.waitOnLaunch():
+ # this requires that RunAsDaemon is set
+ p.wait()
+ else:
+ # this does not require RunAsDaemon to be set, but is slower.
+ #
+ # poll() only catches failures before the call itself
+ # so let's sleep a little first
+ # this does, of course, slow down process launch
+ # which can require an adjustment to the voting interval
+ #
+ # avoid writing a newline or space when polling
+ # so output comes out neatly
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ time.sleep(self._env['poll_launch_time'])
+ p.poll()
+ if p.returncode != None and p.returncode != 0:
+ if self._env['poll_launch_time'] is None:
+ print "Couldn't launch %s (%s): %s" % (self._env['nick'],
+ " ".join(cmdline),
+ p.returncode)
+ else:
+ print ("Couldn't poll %s (%s) "
+ "after waiting %s seconds for launch"
+ ": %s") % (self._env['nick'],
+ " ".join(cmdline),
+ self._env['poll_launch_time'],
+ p.returncode)
return False
return True
@@ -581,6 +604,33 @@ class LocalNodeController(NodeController):
self._env['nick'])
os.remove(lf)
+ def waitOnLaunch(self):
+ """Check whether we can wait() for the tor process to launch"""
+ # TODO: is this the best place for this code?
+ # RunAsDaemon default is 0
+ runAsDaemon = False
+ with open(self._getTorrcFname(), 'r') as f:
+ for line in f.readlines():
+ stline = line.strip()
+ # if the line isn't all whitespace or blank
+ if len(stline) > 0:
+ splline = stline.split()
+ # if the line has at least two tokens on it
+ if (len(splline) > 0
+ and splline[0].lower() == "RunAsDaemon".lower()
+ and splline[1] == "1"):
+ # use the RunAsDaemon value from the torrc
+ # TODO: multiple values?
+ runAsDaemon = True
+ if runAsDaemon:
+ # we must use wait() instead of poll()
+ self._env['poll_launch_time'] = None
+ return True;
+ else:
+ # we must use poll() instead of wait()
+ if self._env['poll_launch_time'] is None:
+ self._env['poll_launch_time'] = self._env['poll_launch_time_default']
+ return False;
DEFAULTS = {
'authority': False,
@@ -605,6 +655,12 @@ DEFAULTS = {
'authorities': "AlternateDirAuthority bleargh bad torrc file!",
'bridges': "Bridge bleargh bad torrc file!",
'core': True,
+ # poll_launch_time: None means wait on launch (requires RunAsDaemon),
+ # otherwise, poll after that many seconds (can be fractional/decimal)
+ 'poll_launch_time': None,
+ # Used when poll_launch_time is None, but RunAsDaemon is not set
+ # Set low so that we don't interfere with the voting interval
+ 'poll_launch_time_default': 0.1,
}
@@ -729,8 +785,19 @@ class Network(object):
self.start()
def start(self):
- print "Starting nodes"
- return all([n.getController().start() for n in self._nodes])
+ if self._dfltEnv['poll_launch_time'] is not None:
+ # format polling correctly - avoid printing a newline
+ sys.stdout.write("Starting nodes")
+ sys.stdout.flush()
+ else:
+ print "Starting nodes"
+ rv = all([n.getController().start() for n in self._nodes])
+ # now print a newline unconditionally - this stops poll()ing
+ # output from being squashed together, at the cost of a blank
+ # line in wait()ing output
+ print ""
+ return rv
+
def hup(self):
print "Sending SIGHUP to nodes"
More information about the tor-commits
mailing list