commit fcf49ad8afe52a36553fabbeaa3741566fa299f6 Author: Damian Johnson atagar@torproject.org Date: Thu May 29 08:48:51 2014 -0700
Close stdout/stderr after the tor process initializes
We use tor's stdout and stderr to determine two things...
* at what stage it has bootstrapped to * errors if tor fails to start
After startup, however, we stop listing to stdout which can cause Tor to lock up if it's registering a lot of NOTICE level messages...
https://trac.torproject.org/projects/tor/ticket/9862
Tested by the following script. Before this fix tor hung after ~3 seconds. With it things happily chug along...
import time
import stem.process
from stem.control import EventType, Controller
tor_process = stem.process.launch_tor_with_config( config = { 'ControlPort': '9051', 'Log': 'DEBUG stdout', }, take_ownership = True, )
with Controller.from_port() as controller: controller.authenticate()
def heartbeat(event): print "%s - %s / %s" % (time.time(), event.read, event.written)
controller.add_event_listener(heartbeat, EventType.BW)
print "Press any key to quit..." raw_input() --- docs/change_log.rst | 7 ++++--- stem/process.py | 3 +++ test/integ/process.py | 2 +- test/runner.py | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index 6b71913..279f2bb 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -52,9 +52,10 @@ The following are only available within Stem's `git repository * Added `support for TB_EMPTY events <api/response.html#stem.response.events.TokenBucketEmptyEvent>`_ (:spec:`6f2919a`) * Added `support for HS_DESC events <api/response.html#stem.response.events.HSDescEvent>`_ (:spec:`a67ac4d`, :trac:`10807`) * Changed :func:`~stem.control.Controller.get_network_status` and :func:`~stem.control.Controller.get_network_statuses` to provide :class:`~stem.descriptor.router_status_entry.RouterStatusEntryMicroV3` if Tor is using microdescriptors (:trac:`7646`) - * The :func:`~stem.connection.connect_port` and :func:`~stem.connection.connect_socket_file` didn't properly mark the Controller it returned as being authenticated, causing event listening among other things to fail. - * The :func:`~stem.control.Controller.add_event_listener` method couldn't accept event types that Stem didn't already recognize. - * The :class:`~stem.exit_policy.ExitPolicy` class couldn't be pickled. + * The :func:`~stem.connection.connect_port` and :func:`~stem.connection.connect_socket_file` didn't properly mark the Controller it returned as being authenticated, causing event listening among other things to fail + * The :func:`~stem.control.Controller.add_event_listener` method couldn't accept event types that Stem didn't already recognize + * The :class:`~stem.exit_policy.ExitPolicy` class couldn't be pickled + * Tor instances spawned with :func:`~stem.process.launch_tor` and :func:`~stem.process.launch_tor_with_config` could hang due to unread stdout content, we now close stdout and stderr once tor finishes bootstrapping (:trac:`9862`)
* **Descriptors**
diff --git a/stem/process.py b/stem/process.py index ad05659..c9fe863 100644 --- a/stem/process.py +++ b/stem/process.py @@ -159,6 +159,9 @@ def launch_tor(tor_cmd = 'tor', args = None, torrc_path = None, completion_perce if timeout: signal.alarm(0) # stop alarm
+ tor_process.stdout.close() + tor_process.stderr.close() + if temp_file: try: os.remove(temp_file) diff --git a/test/integ/process.py b/test/integ/process.py index d87dda4..b06e500 100644 --- a/test/integ/process.py +++ b/test/integ/process.py @@ -65,7 +65,7 @@ class TestProcess(unittest.TestCase): control_socket.close()
tor_process.kill() - tor_process.communicate() + tor_process.wait()
def test_launch_tor_with_timeout(self): """ diff --git a/test/runner.py b/test/runner.py index 3ad78f2..07cbd34 100644 --- a/test/runner.py +++ b/test/runner.py @@ -349,7 +349,7 @@ class Runner(object): except OSError: pass
- self._tor_process.communicate() # blocks until the process is done + self._tor_process.wait() # blocks until the process is done
# if we've made a temporary data directory then clean it up if self._test_dir and CONFIG['integ.test_directory'] == '':