summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Shepelev <temotor@gmail.com>2018-04-15 02:10:57 +0300
committerSergey Shepelev <temotor@gmail.com>2018-04-15 03:16:28 +0300
commit1d6d8924a9da6a0cb839b81e785f99b6ac219a0e (patch)
tree601a925d2d1d5cd82413cfe0fb0f12fd9e14128f
parent69983c6d76e7c122d14a804b5932dfef00d8f7c8 (diff)
downloadeventlet-147-jake.tar.gz
green.threading: current_thread() did not see new monkey-patched threads; Thanks to Jake Tesler147-jake
https://github.com/eventlet/eventlet/issues/172
-rw-r--r--AUTHORS1
-rw-r--r--eventlet/green/threading.py51
-rw-r--r--tests/isolated/patcher_threading_current.py25
-rw-r--r--tests/patcher_test.py21
4 files changed, 62 insertions, 36 deletions
diff --git a/AUTHORS b/AUTHORS
index 1d277c6..107f565 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -165,3 +165,4 @@ Thanks To
* orishoshan
* Matt Bennett
* Ralf Haferkamp
+* Jake Tesler
diff --git a/eventlet/green/threading.py b/eventlet/green/threading.py
index 3176261..a25a1f1 100644
--- a/eventlet/green/threading.py
+++ b/eventlet/green/threading.py
@@ -1,5 +1,5 @@
"""Implements the standard threading module, using greenthreads."""
-from eventlet import patcher
+import eventlet
from eventlet.green import thread
from eventlet.green import time
from eventlet.support import greenlets as greenlet, six
@@ -13,18 +13,17 @@ if six.PY2:
else:
__patched__ += ['get_ident', '_set_sentinel']
-__orig_threading = patcher.original('threading')
+__orig_threading = eventlet.patcher.original('threading')
__threadlocal = __orig_threading.local()
+__patched_enumerate = None
-patcher.inject(
+eventlet.patcher.inject(
'threading',
globals(),
('thread' if six.PY2 else '_thread', thread),
('time', time))
-del patcher
-
_count = 1
@@ -89,6 +88,7 @@ def _fixup_thread(t):
def current_thread():
+ global __patched_enumerate
g = greenlet.getcurrent()
if not g:
# Not currently in a greenthread, fall back to standard function
@@ -99,21 +99,34 @@ def current_thread():
except AttributeError:
active = __threadlocal.active = {}
+ g_id = id(g)
+ t = active.get(g_id)
+ if t is not None:
+ return t
+
+ # FIXME: move import from function body to top
+ # (jaketesler@github) Furthermore, I was unable to have the current_thread() return correct results from
+ # threading.enumerate() unless the enumerate() function was a) imported at runtime using the gross __import__() call
+ # and b) was hot-patched using patch_function().
+ # https://github.com/eventlet/eventlet/issues/172#issuecomment-379421165
+ if __patched_enumerate is None:
+ __patched_enumerate = eventlet.patcher.patch_function(__import__('threading').enumerate)
+ found = [th for th in __patched_enumerate() if th.ident == g_id]
+ if found:
+ return found[0]
+
+ # Add green thread to active if we can clean it up on exit
+ def cleanup(g):
+ del active[g_id]
try:
- t = active[id(g)]
- except KeyError:
- # Add green thread to active if we can clean it up on exit
- def cleanup(g):
- del active[id(g)]
- try:
- g.link(cleanup)
- except AttributeError:
- # Not a GreenThread type, so there's no way to hook into
- # the green thread exiting. Fall back to the standard
- # function then.
- t = _fixup_thread(__orig_threading.currentThread())
- else:
- t = active[id(g)] = _GreenThread(g)
+ g.link(cleanup)
+ except AttributeError:
+ # Not a GreenThread type, so there's no way to hook into
+ # the green thread exiting. Fall back to the standard
+ # function then.
+ t = _fixup_thread(__orig_threading.current_thread())
+ else:
+ t = active[g_id] = _GreenThread(g)
return t
diff --git a/tests/isolated/patcher_threading_current.py b/tests/isolated/patcher_threading_current.py
new file mode 100644
index 0000000..2eb6676
--- /dev/null
+++ b/tests/isolated/patcher_threading_current.py
@@ -0,0 +1,25 @@
+# Threading.current_thread does not change when using greenthreads?
+# https://github.com/eventlet/eventlet/issues/172
+__test__ = False
+
+if __name__ == '__main__':
+ import eventlet
+ eventlet.monkey_patch()
+
+ import threading
+
+ g = set()
+
+ def fun():
+ ct = threading.current_thread()
+ g.add(ct.name)
+
+ ts = tuple(threading.Thread(target=fun, name='t{}'.format(i)) for i in range(3))
+ for t in ts:
+ t.start()
+ for t in ts:
+ t.join()
+
+ assert g == set(('t0', 't1', 't2')), repr(g)
+
+ print('pass')
diff --git a/tests/patcher_test.py b/tests/patcher_test.py
index ff59400..00ee31f 100644
--- a/tests/patcher_test.py
+++ b/tests/patcher_test.py
@@ -312,23 +312,6 @@ print(len(_threading._active))
assert lines[1] == '1', lines
assert lines[2] == '1', lines
- def test_threading(self):
- new_mod = """import eventlet
-eventlet.monkey_patch()
-import threading
-def test():
- print(repr(threading.currentThread()))
-t = threading.Thread(target=test)
-t.start()
-t.join()
-print(len(threading._active))
-"""
- self.write_to_tempfile("newmod", new_mod)
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(len(lines), 3, "\n".join(lines))
- assert lines[0].startswith('<_MainThread'), lines[0]
- self.assertEqual(lines[1], "1", lines[1])
-
def test_tpool(self):
new_mod = """import eventlet
eventlet.monkey_patch()
@@ -520,3 +503,7 @@ def test_blocking_select_methods_are_deleted():
def test_regular_file_readall():
tests.run_isolated('regular_file_readall.py')
+
+
+def test_threading_current():
+ tests.run_isolated('patcher_threading_current.py')