Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix second simultaneous read (parallel paramiko issue)
#94 Because of the way paramiko utilises a client thread to manage its communication, it's not been compatible with eventlet when run in parallel. It's not the only place these problems would arise. This stemmed from the reuse of a fileno by the underlying OS. Because listeners are registered against this descriptor, it would be possible for old listeners to receive events destined for newer descriptors; occasionally code would attempt to utilise the new descriptor from a different greenlet, giving rise to the 'second simultaneous read' problem. Whenever a Python object is created to wrap one of these filenos, we now signal the hub in order that it can correctly obsolete extant listeners against that fileno. This is a fairly tricky operation, due to the way that listeners' threads are interleaved with the hub's operation - there are a number of small fixes here to defend against one listener from effectively obsoleting another when an event is pending against it.
- Loading branch information
Showing
11 changed files
with
362 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
""" | ||
In order to detect a filehandle that's been closed, our only clue may be | ||
the operating system returning the same filehandle in response to some | ||
other operation. | ||
The builtins 'file' and 'open' are patched to collaborate with the | ||
notify_opened protocol. | ||
""" | ||
|
||
builtins_orig = __builtins__ | ||
|
||
from eventlet import hubs | ||
from eventlet.hubs import hub | ||
from eventlet.patcher import slurp_properties | ||
import sys | ||
|
||
__all__ = dir(builtins_orig) | ||
__patched__ = ['file', 'open'] | ||
|
||
slurp_properties(builtins_orig, globals(), | ||
ignore=__patched__, srckeys=dir(builtins_orig)) | ||
|
||
hubs.get_hub() | ||
|
||
__original_file = file | ||
class file(__original_file): | ||
def __init__(self, *args, **kwargs): | ||
super(file, self).__init__(*args, **kwargs) | ||
hubs.notify_opened(self.fileno()) | ||
|
||
__original_open = open | ||
__opening = False | ||
def open(*args): | ||
global __opening | ||
result = __original_open(*args) | ||
if not __opening: | ||
# This is incredibly ugly. 'open' is used under the hood by | ||
# the import process. So, ensure we don't wind up in an | ||
# infinite loop. | ||
__opening = True | ||
hubs.notify_opened(result.fileno()) | ||
__opening = False | ||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.