"""Implements the standard threading module, using greenthreads.""" from eventlet import patcher from eventlet.green import thread from eventlet.green import time from eventlet.support import greenlets as greenlet, six __patched__ = ['_start_new_thread', '_allocate_lock', '_sleep', 'local', 'stack_size', 'Lock', 'currentThread', 'current_thread', '_after_fork', '_shutdown'] if six.PY2: __patched__ += ['_get_ident'] else: __patched__ += ['get_ident', '_set_sentinel'] __orig_threading = patcher.original('threading') __threadlocal = __orig_threading.local() patcher.inject( 'threading', globals(), ('thread' if six.PY2 else '_thread', thread), ('time', time)) del patcher _count = 1 class _GreenThread(object): """Wrapper for GreenThread objects to provide Thread-like attributes and methods""" def __init__(self, g): global _count self._g = g self._name = 'GreenThread-%d' % _count _count += 1 def __repr__(self): return '<_GreenThread(%s, %r)>' % (self._name, self._g) def join(self, timeout=None): return self._g.wait() def getName(self): return self._name get_name = getName def setName(self, name): self._name = str(name) set_name = setName name = property(getName, setName) ident = property(lambda self: id(self._g)) def isAlive(self): return True is_alive = isAlive daemon = property(lambda self: True) def isDaemon(self): return self.daemon is_daemon = isDaemon __threading = None def _fixup_thread(t): # Some third-party packages (lockfile) will try to patch the # threading.Thread class with a get_name attribute if it doesn't # exist. Since we might return Thread objects from the original # threading package that won't get patched, let's make sure each # individual object gets patched too our patched threading.Thread # class has been patched. This is why monkey patching can be bad... global __threading if not __threading: __threading = __import__('threading') if (hasattr(__threading.Thread, 'get_name') and not hasattr(t, 'get_name')): t.get_name = t.getName return t def current_thread(): g = greenlet.getcurrent() if not g: # Not currently in a greenthread, fall back to standard function return _fixup_thread(__orig_threading.current_thread()) try: active = __threadlocal.active except AttributeError: active = __threadlocal.active = {} 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) return t currentThread = current_thread