summaryrefslogtreecommitdiff
path: root/paramiko/pipe.py
diff options
context:
space:
mode:
authorRobey Pointer <robey@lag.net>2007-10-28 20:03:44 -0700
committerRobey Pointer <robey@lag.net>2007-10-28 20:03:44 -0700
commite3d9b90ea1f25792e652a0809b37b52635243932 (patch)
treec6b99f4940f2ceec7941500839d860119d0609fb /paramiko/pipe.py
parent80b9e289cef4fc0939141ccf15751017a58a1637 (diff)
downloadparamiko-e3d9b90ea1f25792e652a0809b37b52635243932.tar.gz
[project @ robey@lag.net-20071029030344-9adfzb9ulfodtepu]
bug 157205: select() doesn't notify incoming stderr data, because stderr's pipe isn't hooked up to the fileno() BufferedPipe. to fix, i added an "or" pipe-event that can be triggered by either stdout or stderr, and hooked them both up to fileno(). added a unit test for the bug and one for the "or" pipe.
Diffstat (limited to 'paramiko/pipe.py')
-rw-r--r--paramiko/pipe.py38
1 files changed, 36 insertions, 2 deletions
diff --git a/paramiko/pipe.py b/paramiko/pipe.py
index d71ca167..1cfed2d0 100644
--- a/paramiko/pipe.py
+++ b/paramiko/pipe.py
@@ -19,6 +19,9 @@
"""
Abstraction of a one-way pipe where the read end can be used in select().
Normally this is trivial, but Windows makes it nearly impossible.
+
+The pipe acts like an Event, which can be set or cleared. When set, the pipe
+will trigger as readable in select().
"""
import sys
@@ -57,7 +60,7 @@ class PosixPipe (object):
self._set = False
def set (self):
- if self._set:
+ if self._set or self._closed:
return
self._set = True
os.write(self._wfd, '*')
@@ -103,7 +106,7 @@ class WindowsPipe (object):
self._set = False
def set (self):
- if self._set:
+ if self._set or self._closed:
return
self._set = True
self._wsock.send('*')
@@ -111,3 +114,34 @@ class WindowsPipe (object):
def set_forever (self):
self._forever = True
self.set()
+
+
+class OrPipe (object):
+ def __init__(self, pipe):
+ self._set = False
+ self._partner = None
+ self._pipe = pipe
+
+ def set(self):
+ self._set = True
+ if not self._partner._set:
+ self._pipe.set()
+
+ def clear(self):
+ self._set = False
+ if not self._partner._set:
+ self._pipe.clear()
+
+
+def make_or_pipe(pipe):
+ """
+ wraps a pipe into two pipe-like objects which are "or"d together to
+ affect the real pipe. if either returned pipe is set, the wrapped pipe
+ is set. when both are cleared, the wrapped pipe is cleared.
+ """
+ p1 = OrPipe(pipe)
+ p2 = OrPipe(pipe)
+ p1._partner = p2
+ p2._partner = p1
+ return p1, p2
+