Skip to content

Commit

Permalink
Merge branch '1.17' into 2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bitprophet committed Jun 10, 2016
2 parents 632b92c + da125c1 commit 50de173
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 8 deletions.
4 changes: 2 additions & 2 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Older junk
tox>=1.4,<1.5
# For newer tasks like building Sphinx docs.
invoke>=0.11.1,<2.0
invocations>=0.11.0,<2.0
invoke>=0.13,<2.0
invocations>=0.13,<2.0
sphinx>=1.1.3,<2.0
alabaster>=0.7.5,<2.0
releases>=1.1.0,<2.0
Expand Down
19 changes: 14 additions & 5 deletions paramiko/buffered_pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,20 @@ def set_event(self, event):
:param threading.Event event: the event to set/clear
"""
self._event = event
if len(self._buffer) > 0:
event.set()
else:
event.clear()
self._lock.acquire()
try:
self._event = event
# Make sure the event starts in `set` state if we appear to already
# be closed; otherwise, if we start in `clear` state & are closed,
# nothing will ever call `.feed` and the event (& OS pipe, if we're
# wrapping one - see `Channel.fileno`) will permanently stay in
# `clear`, causing deadlock if e.g. `select`ed upon.
if self._closed or len(self._buffer) > 0:
event.set()
else:
event.clear()
finally:
self._lock.release()

def feed(self, data):
"""
Expand Down
7 changes: 7 additions & 0 deletions sites/www/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
Changelog
=========

* :bug:`537` Fix a bug in `BufferedPipe.set_event
<paramiko.buffered_pipe.BufferedPipe.set_event>` which could cause
deadlocks/hangs when one uses `select.select` against
`~paramiko.channel.Channel` objects (or otherwise calls `Channel.fileno
<paramiko.channel.Channel.fileno>` after the channel has closed). Thanks to
Przemysław Strzelczak for the report & reproduction case, and to Krzysztof
Rusek for the fix.
* :release:`2.0.0 <2016-04-28>`
* :release:`1.17.0 <2016-04-28>`
* :release:`1.16.1 <2016-04-28>`
Expand Down
2 changes: 1 addition & 1 deletion tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from os.path import join
from shutil import rmtree, copytree

from invoke import Collection, ctask as task
from invoke import Collection, task
from invocations.docs import docs, www, sites
from invocations.packaging import publish

Expand Down
18 changes: 18 additions & 0 deletions tests/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,3 +828,21 @@ def read_message(self):
hostkey=public_host_key,
username='slowdive',
password='pygmalion')

def test_M_select_after_close(self):
"""
verify that select works when a channel is already closed.
"""
self.setup_test_server()
chan = self.tc.open_session()
chan.invoke_shell()
schan = self.ts.accept(1.0)
schan.close()

# give client a moment to receive close notification
time.sleep(0.1)

r, w, e = select.select([chan], [], [], 0.1)
self.assertEqual([chan], r)
self.assertEqual([], w)
self.assertEqual([], e)

0 comments on commit 50de173

Please sign in to comment.