summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Stasiak <jakub@stasiak.at>2015-11-12 02:05:25 +0100
committerSergey Shepelev <temotor@gmail.com>2015-11-24 20:30:44 +0300
commit2c8722ae7e3489165feeb7e8daf0f8eeeecd555c (patch)
treee630ceeaf0e7f77aaa9a464cdb844f5fe7f0bb22
parent3ae710e70ecb3683f83b9829011de01b5d3e0bf4 (diff)
downloadeventlet-test.tar.gz
Fix HTTPServer.serve_forever blocking whole processtest
Original report: https://github.com/eventlet/eventlet/issues/249 Explanation is in the comments in the code.
-rw-r--r--eventlet/green/selectors.py20
-rw-r--r--eventlet/patcher.py8
-rw-r--r--tests/isolated/patcher_socketserver_selectors.py28
-rw-r--r--tests/patcher_test.py4
4 files changed, 59 insertions, 1 deletions
diff --git a/eventlet/green/selectors.py b/eventlet/green/selectors.py
index 26427ec..9d482fe 100644
--- a/eventlet/green/selectors.py
+++ b/eventlet/green/selectors.py
@@ -3,9 +3,29 @@ import sys
from eventlet import patcher
from eventlet.green import select
+__patched__ = [
+ 'SelectSelector',
+ 'PollSelector',
+ 'EpollSelector',
+ 'DevpollSelector',
+ 'KqueueSelector',
+]
+
patcher.inject('selectors', globals(), ('select', select))
del patcher
if sys.platform != 'win32':
SelectSelector._select = staticmethod(select.select)
+
+
+# We only have green select so the options are:
+# * leave it be and have selectors that block
+# * try to pretend the "bad" selectors don't exist
+# * replace all with SelectSelector for the price of possibly different
+# performance characteristic and missing fileno() method (if someone
+# uses it it'll result in a crash, we may want to implement it in the future)
+PollSelector = SelectSelector
+EpollSelector = SelectSelector
+DevpollSelector = SelectSelector
+KqueueSelector = SelectSelector
diff --git a/eventlet/patcher.py b/eventlet/patcher.py
index eb09f9a..40207f9 100644
--- a/eventlet/patcher.py
+++ b/eventlet/patcher.py
@@ -331,7 +331,13 @@ def _green_os_modules():
def _green_select_modules():
from eventlet.green import select
- return [('select', select)]
+ modules = [('select', select)]
+
+ if sys.version_info >= (3, 4):
+ from eventlet.green import selectors
+ modules.append(('selectors', selectors))
+
+ return modules
def _green_socket_modules():
diff --git a/tests/isolated/patcher_socketserver_selectors.py b/tests/isolated/patcher_socketserver_selectors.py
new file mode 100644
index 0000000..97df6e2
--- /dev/null
+++ b/tests/isolated/patcher_socketserver_selectors.py
@@ -0,0 +1,28 @@
+if __name__ == '__main__':
+ import eventlet
+ eventlet.monkey_patch()
+
+ from eventlet.support.six.moves.BaseHTTPServer import (
+ HTTPServer,
+ BaseHTTPRequestHandler,
+ )
+ import threading
+
+ server = HTTPServer(('localhost', 0), BaseHTTPRequestHandler)
+ thread = threading.Thread(target=server.serve_forever)
+
+ # Before fixing it the code would never go pass this line because:
+ # * socketserver.BaseServer that's used behind the scenes here uses
+ # selectors.PollSelector if it's available and we don't have green poll
+ # implementation so this just couldn't work
+ # * making socketserver use selectors.SelectSelector wasn't enough as
+ # until now we just failed to monkey patch selectors module
+ #
+ # Due to the issues above this thread.start() call effectively behaved
+ # like calling server.serve_forever() directly in the current thread
+ #
+ # Original report: https://github.com/eventlet/eventlet/issues/249
+ thread.start()
+
+ server.shutdown()
+ print('pass')
diff --git a/tests/patcher_test.py b/tests/patcher_test.py
index 2e458c5..deae8ef 100644
--- a/tests/patcher_test.py
+++ b/tests/patcher_test.py
@@ -506,3 +506,7 @@ def test_threading_condition():
def test_threading_join():
tests.run_isolated('patcher_threading_join.py')
+
+
+def test_socketserver_selectors():
+ tests.run_isolated('patcher_socketserver_selectors.py')