844b699
diff -Naur eventlet-0.9.16.orig/eventlet/green/threading.py eventlet-0.9.16/eventlet/green/threading.py
844b699
--- eventlet-0.9.16.orig/eventlet/green/threading.py	2010-06-07 19:15:37.000000000 +0000
844b699
+++ eventlet-0.9.16/eventlet/green/threading.py	2012-03-05 20:08:51.932476383 +0000
f97c515
@@ -1,9 +1,16 @@
f97c515
+"""Implements the standard threading module, using greenthreads."""
f97c515
 from eventlet import patcher
f97c515
 from eventlet.green import thread
f97c515
 from eventlet.green import time
f97c515
+from eventlet.support import greenlets as greenlet
f97c515
 
f97c515
 __patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident', '_sleep',
f97c515
-               'local', 'stack_size', 'Lock']
f97c515
+               'local', 'stack_size', 'Lock', 'currentThread',
844b699
+               'current_thread', '_after_fork']
f97c515
+
f97c515
+__orig_threading = patcher.original('threading')
f97c515
+__threadlocal = __orig_threading.local()
f97c515
+
f97c515
 
f97c515
 patcher.inject('threading',
f97c515
     globals(),
844b699
@@ -11,3 +18,103 @@
f97c515
     ('time', time))
f97c515
 
f97c515
 del patcher
f97c515
+
f97c515
+
f97c515
+_count = 1
f97c515
+class _GreenThread(object):
f97c515
+    """Wrapper for GreenThread objects to provide Thread-like attributes
f97c515
+    and methods"""
f97c515
+    def __init__(self, g):
f97c515
+        global _count
f97c515
+        self._g = g
f97c515
+        self._name = 'GreenThread-%d' % _count
f97c515
+        _count += 1
f97c515
+
f97c515
+    def __repr__(self):
f97c515
+        return '<_GreenThread(%s, %r)>' % (self._name, self._g)
f97c515
+
844b699
+    def join(self, timeout=None):
844b699
+        return self._g.wait()
844b699
+
f97c515
+    @property
f97c515
+    def name(self):
f97c515
+        return self._name
f97c515
+
844b699
+    @name.setter
844b699
+    def name(self, name):
844b699
+        self._name = str(name)
844b699
+
f97c515
+    def getName(self):
f97c515
+        return self.name
f97c515
+    get_name = getName
f97c515
+
844b699
+    def setName(self, name):
844b699
+        self.name = name
844b699
+    set_name = setName
844b699
+
844b699
+    @property
844b699
+    def ident(self):
844b699
+        return id(self._g)
844b699
+
844b699
+    def isAlive(self):
844b699
+        return True
844b699
+    is_alive = isAlive
844b699
+
844b699
+    @property
844b699
+    def daemon(self):
844b699
+        return True
844b699
+
844b699
+    def isDaemon(self):
844b699
+        return self.daemon
844b699
+    is_daemon = isDaemon
f97c515
+
f97c515
+
f97c515
+__threading = None
f97c515
+
f97c515
+def _fixup_thread(t):
f97c515
+    # Some third-party packages (lockfile) will try to patch the
f97c515
+    # threading.Thread class with a get_name attribute if it doesn't
f97c515
+    # exist. Since we might return Thread objects from the original
f97c515
+    # threading package that won't get patched, let's make sure each
f97c515
+    # individual object gets patched too our patched threading.Thread
f97c515
+    # class has been patched. This is why monkey patching can be bad...
f97c515
+    global __threading
f97c515
+    if not __threading:
f97c515
+        __threading = __import__('threading')
f97c515
+
f97c515
+    if (hasattr(__threading.Thread, 'get_name') and
f97c515
+        not hasattr(t, 'get_name')):
f97c515
+        t.get_name = t.getName
f97c515
+    return t
f97c515
+
f97c515
+
f97c515
+def current_thread():
f97c515
+    g = greenlet.getcurrent()
f97c515
+    if not g:
f97c515
+        # Not currently in a greenthread, fall back to standard function
f97c515
+        return _fixup_thread(__orig_threading.current_thread())
f97c515
+
f97c515
+    try:
f97c515
+        active = __threadlocal.active
f97c515
+    except AttributeError:
f97c515
+        active = __threadlocal.active = {}
f97c515
+    
f97c515
+    try:
f97c515
+        t = active[id(g)]
f97c515
+    except KeyError:
f97c515
+        # Add green thread to active if we can clean it up on exit
f97c515
+        def cleanup(g):
f97c515
+            del active[id(g)]
f97c515
+        try:
f97c515
+            g.link(cleanup)
f97c515
+        except AttributeError:
f97c515
+            # Not a GreenThread type, so there's no way to hook into
f97c515
+            # the green thread exiting. Fall back to the standard
f97c515
+            # function then.
f97c515
+            t = _fixup_thread(__orig_threading.current_thread())
f97c515
+        else:
f97c515
+            t = active[id(g)] = _GreenThread(g)
f97c515
+
f97c515
+    return t
f97c515
+
f97c515
+currentThread = current_thread
844b699
diff -Naur eventlet-0.9.16.orig/eventlet/patcher.py eventlet-0.9.16/eventlet/patcher.py
844b699
--- eventlet-0.9.16.orig/eventlet/patcher.py	2011-04-11 06:56:59.000000000 +0000
844b699
+++ eventlet-0.9.16/eventlet/patcher.py	2012-03-05 20:08:45.749398303 +0000
f97c515
@@ -223,7 +223,6 @@
f97c515
         on.setdefault(modname, default_on)
f97c515
         
f97c515
     modules_to_patch = []
f97c515
-    patched_thread = False
f97c515
     if on['os'] and not already_patched.get('os'):
f97c515
         modules_to_patch += _green_os_modules()
f97c515
         already_patched['os'] = True
f97c515
@@ -234,7 +233,6 @@
f97c515
         modules_to_patch += _green_socket_modules()
f97c515
         already_patched['socket'] = True
f97c515
     if on['thread'] and not already_patched.get('thread'):
f97c515
-        patched_thread = True
f97c515
         modules_to_patch += _green_thread_modules()
f97c515
         already_patched['thread'] = True
f97c515
     if on['time'] and not already_patched.get('time'):
f97c515
@@ -266,27 +264,9 @@
f97c515
                 patched_attr = getattr(mod, attr_name, None)
f97c515
                 if patched_attr is not None:
f97c515
                     setattr(orig_mod, attr_name, patched_attr)
f97c515
-
f97c515
-        # hacks ahead; this is necessary to prevent a KeyError on program exit
f97c515
-        if patched_thread:
f97c515
-            _patch_main_thread(sys.modules['threading'])
f97c515
     finally:
f97c515
         imp.release_lock()
f97c515
 
f97c515
-def _patch_main_thread(mod):
f97c515
-    """This is some gnarly patching specific to the threading module;
f97c515
-    threading will always be initialized prior to monkeypatching, and
f97c515
-    its _active dict will have the wrong key (it uses the real thread
f97c515
-    id but once it's patched it will use the greenlet ids); so what we
f97c515
-    do is rekey the _active dict so that the main thread's entry uses
f97c515
-    the greenthread key.  Other threads' keys are ignored."""
f97c515
-    thread = original('thread')
f97c515
-    curthread = mod._active.pop(thread.get_ident(), None)
f97c515
-    if curthread:
f97c515
-        import eventlet.green.thread
f97c515
-        mod._active[eventlet.green.thread.get_ident()] = curthread
f97c515
-
f97c515
-
f97c515
 def is_monkey_patched(module):
f97c515
     """Returns True if the given module is monkeypatched currently, False if
f97c515
     not.  *module* can be either the module itself or its name.
844b699
diff -Naur eventlet-0.9.16.orig/tests/patcher_test.py eventlet-0.9.16/tests/patcher_test.py
844b699
--- eventlet-0.9.16.orig/tests/patcher_test.py	2011-02-16 00:59:54.000000000 +0000
844b699
+++ eventlet-0.9.16/tests/patcher_test.py	2012-03-05 20:08:51.933476395 +0000
844b699
@@ -293,5 +293,175 @@
f97c515
         self.assertEqual(output, "done\n", output)
f97c515
 
f97c515
 
f97c515
+class Threading(ProcessBase):
f97c515
+    def test_orig_thread(self):
f97c515
+        new_mod = """import eventlet
f97c515
+eventlet.monkey_patch()
f97c515
+from eventlet import patcher
f97c515
+import threading
f97c515
+_threading = patcher.original('threading')
f97c515
+def test():
f97c515
+    print repr(threading.current_thread())
f97c515
+t = _threading.Thread(target=test)
f97c515
+t.start()
f97c515
+t.join()
f97c515
+print len(threading._active)
f97c515
+print len(_threading._active)
f97c515
+"""
f97c515
+        self.write_to_tempfile("newmod", new_mod)
f97c515
+        output, lines = self.launch_subprocess('newmod')
f97c515
+        self.assertEqual(len(lines), 4, "\n".join(lines))
f97c515
+        self.assert_(lines[0].startswith('
f97c515
+        self.assertEqual(lines[1], "1", lines[1])
f97c515
+        self.assertEqual(lines[2], "1", lines[2])
f97c515
+
f97c515
+    def test_threading(self):
f97c515
+        new_mod = """import eventlet
f97c515
+eventlet.monkey_patch()
f97c515
+import threading
f97c515
+def test():
f97c515
+    print repr(threading.current_thread())
f97c515
+t = threading.Thread(target=test)
f97c515
+t.start()
f97c515
+t.join()
f97c515
+print len(threading._active)
f97c515
+"""
f97c515
+        self.write_to_tempfile("newmod", new_mod)
f97c515
+        output, lines = self.launch_subprocess('newmod')
f97c515
+        self.assertEqual(len(lines), 3, "\n".join(lines))
f97c515
+        self.assert_(lines[0].startswith('<_MainThread'), lines[0])
f97c515
+        self.assertEqual(lines[1], "1", lines[1])
f97c515
+
f97c515
+    def test_tpool(self):
f97c515
+        new_mod = """import eventlet
f97c515
+eventlet.monkey_patch()
f97c515
+from eventlet import tpool
f97c515
+import threading
f97c515
+def test():
f97c515
+    print repr(threading.current_thread())
f97c515
+tpool.execute(test)
f97c515
+print len(threading._active)
f97c515
+"""
f97c515
+        self.write_to_tempfile("newmod", new_mod)
f97c515
+        output, lines = self.launch_subprocess('newmod')
f97c515
+        self.assertEqual(len(lines), 3, "\n".join(lines))
f97c515
+        self.assert_(lines[0].startswith('
f97c515
+        self.assertEqual(lines[1], "1", lines[1])
f97c515
+
f97c515
+    def test_greenlet(self):
f97c515
+        new_mod = """import eventlet
f97c515
+eventlet.monkey_patch()
f97c515
+from eventlet import event
f97c515
+import threading
f97c515
+evt = event.Event()
f97c515
+def test():
f97c515
+    print repr(threading.current_thread())
f97c515
+    evt.send()
f97c515
+eventlet.spawn_n(test)
f97c515
+evt.wait()
f97c515
+print len(threading._active)
f97c515
+"""
f97c515
+        self.write_to_tempfile("newmod", new_mod)
f97c515
+        output, lines = self.launch_subprocess('newmod')
f97c515
+        self.assertEqual(len(lines), 3, "\n".join(lines))
f97c515
+        self.assert_(lines[0].startswith('<_MainThread'), lines[0])
f97c515
+        self.assertEqual(lines[1], "1", lines[1])
f97c515
+
f97c515
+    def test_greenthread(self):
f97c515
+        new_mod = """import eventlet
f97c515
+eventlet.monkey_patch()
f97c515
+import threading
f97c515
+def test():
f97c515
+    print repr(threading.current_thread())
f97c515
+t = eventlet.spawn(test)
f97c515
+t.wait()
f97c515
+print len(threading._active)
f97c515
+"""
f97c515
+        self.write_to_tempfile("newmod", new_mod)
f97c515
+        output, lines = self.launch_subprocess('newmod')
f97c515
+        self.assertEqual(len(lines), 3, "\n".join(lines))
f97c515
+        self.assert_(lines[0].startswith('<_GreenThread'), lines[0])
f97c515
+        self.assertEqual(lines[1], "1", lines[1])
f97c515
+
844b699
+
844b699
+class GreenThreadWrapper(ProcessBase):
844b699
+    prologue = """import eventlet
844b699
+eventlet.monkey_patch()
844b699
+import threading
844b699
+def test():
844b699
+    t = threading.current_thread()
844b699
+"""
844b699
+    epilogue = """
844b699
+t = eventlet.spawn(test)
844b699
+t.wait()
844b699
+"""
844b699
+
844b699
+    def test_join(self):
844b699
+        self.write_to_tempfile("newmod", self.prologue + """
844b699
+    def test2():
844b699
+        global t2
844b699
+        t2 = threading.current_thread()
844b699
+    eventlet.spawn(test2)
844b699
+""" + self.epilogue + """
844b699
+print repr(t2)
844b699
+t2.join()
844b699
+""")
844b699
+        output, lines = self.launch_subprocess('newmod')
844b699
+        self.assertEqual(len(lines), 2, "\n".join(lines))
844b699
+        self.assert_(lines[0].startswith('<_GreenThread'), lines[0])
844b699
+
844b699
+    def test_name(self):
844b699
+        self.write_to_tempfile("newmod", self.prologue + """
844b699
+    print t.name
844b699
+    print t.getName()
844b699
+    print t.get_name()
844b699
+    t.name = 'foo'
844b699
+    print t.name
844b699
+    print t.getName()
844b699
+    print t.get_name()
844b699
+    t.setName('bar')
844b699
+    print t.name
844b699
+    print t.getName()
844b699
+    print t.get_name()
844b699
+""" + self.epilogue)
844b699
+        output, lines = self.launch_subprocess('newmod')
844b699
+        self.assertEqual(len(lines), 10, "\n".join(lines))
844b699
+        for i in xrange(0, 3):
844b699
+            self.assertEqual(lines[i], "GreenThread-1", lines[i])
844b699
+        for i in xrange(3, 6):
844b699
+            self.assertEqual(lines[i], "foo", lines[i])
844b699
+        for i in xrange(6, 9):
844b699
+            self.assertEqual(lines[i], "bar", lines[i])
844b699
+
844b699
+    def test_ident(self):
844b699
+        self.write_to_tempfile("newmod", self.prologue + """
844b699
+    print id(t._g)
844b699
+    print t.ident
844b699
+""" + self.epilogue)
844b699
+        output, lines = self.launch_subprocess('newmod')
844b699
+        self.assertEqual(len(lines), 3, "\n".join(lines))
844b699
+        self.assertEqual(lines[0], lines[1])
844b699
+
844b699
+    def test_is_alive(self):
844b699
+        self.write_to_tempfile("newmod", self.prologue + """
844b699
+    print t.is_alive()
844b699
+    print t.isAlive()
844b699
+""" + self.epilogue)
844b699
+        output, lines = self.launch_subprocess('newmod')
844b699
+        self.assertEqual(len(lines), 3, "\n".join(lines))
844b699
+        self.assertEqual(lines[0], "True", lines[0])
844b699
+        self.assertEqual(lines[1], "True", lines[1])
844b699
+
844b699
+    def test_is_daemon(self):
844b699
+        self.write_to_tempfile("newmod", self.prologue + """
844b699
+    print t.is_daemon()
844b699
+    print t.isDaemon()
844b699
+""" + self.epilogue)
844b699
+        output, lines = self.launch_subprocess('newmod')
844b699
+        self.assertEqual(len(lines), 3, "\n".join(lines))
844b699
+        self.assertEqual(lines[0], "True", lines[0])
844b699
+        self.assertEqual(lines[1], "True", lines[1])
844b699
+
844b699
+
f97c515
 if __name__ == '__main__':
f97c515
     main()