codekingpro/portable-devtools
114k
1"""Implements the standard threading module, using greenthreads."""2import eventlet3from eventlet.green import thread4from eventlet.green import time5from eventlet.support import greenlets as greenlet6import six7 8__patched__ = ['_start_new_thread', '_allocate_lock',9 '_sleep', 'local', 'stack_size', 'Lock', 'currentThread',10 'current_thread', '_after_fork', '_shutdown']11 12if six.PY2:13 __patched__ += ['_get_ident']14else:15 __patched__ += ['get_ident', '_set_sentinel']16 17__orig_threading = eventlet.patcher.original('threading')18__threadlocal = __orig_threading.local()19__patched_enumerate = None20 21 22eventlet.patcher.inject(23 'threading',24 globals(),25 ('thread' if six.PY2 else '_thread', thread),26 ('time', time))27 28 29_count = 130 31 32class _GreenThread(object):33 """Wrapper for GreenThread objects to provide Thread-like attributes34 and methods"""35 36 def __init__(self, g):37 global _count38 self._g = g39 self._name = 'GreenThread-%d' % _count40 _count += 141 42 def __repr__(self):43 return '<_GreenThread(%s, %r)>' % (self._name, self._g)44 45 def join(self, timeout=None):46 return self._g.wait()47 48 def getName(self):49 return self._name50 get_name = getName51 52 def setName(self, name):53 self._name = str(name)54 set_name = setName55 56 name = property(getName, setName)57 58 ident = property(lambda self: id(self._g))59 60 def isAlive(self):61 return True62 is_alive = isAlive63 64 daemon = property(lambda self: True)65 66 def isDaemon(self):67 return self.daemon68 is_daemon = isDaemon69 70 71__threading = None72 73 74def _fixup_thread(t):75 # Some third-party packages (lockfile) will try to patch the76 # threading.Thread class with a get_name attribute if it doesn't77 # exist. Since we might return Thread objects from the original78 # threading package that won't get patched, let's make sure each79 # individual object gets patched too our patched threading.Thread80 # class has been patched. This is why monkey patching can be bad...81 global __threading82 if not __threading:83 __threading = __import__('threading')84 85 if (hasattr(__threading.Thread, 'get_name') and86 not hasattr(t, 'get_name')):87 t.get_name = t.getName88 return t89 90 91def current_thread():92 global __patched_enumerate93 g = greenlet.getcurrent()94 if not g:95 # Not currently in a greenthread, fall back to standard function96 return _fixup_thread(__orig_threading.current_thread())97 98 try:99 active = __threadlocal.active100 except AttributeError:101 active = __threadlocal.active = {}102 103 g_id = id(g)104 t = active.get(g_id)105 if t is not None:106 return t107 108 # FIXME: move import from function body to top109 # (jaketesler@github) Furthermore, I was unable to have the current_thread() return correct results from110 # threading.enumerate() unless the enumerate() function was a) imported at runtime using the gross __import__() call111 # and b) was hot-patched using patch_function().112 # https://github.com/eventlet/eventlet/issues/172#issuecomment-379421165113 if __patched_enumerate is None:114 __patched_enumerate = eventlet.patcher.patch_function(__import__('threading').enumerate)115 found = [th for th in __patched_enumerate() if th.ident == g_id]116 if found:117 return found[0]118 119 # Add green thread to active if we can clean it up on exit120 def cleanup(g):121 del active[g_id]122 try:123 g.link(cleanup)124 except AttributeError:125 # Not a GreenThread type, so there's no way to hook into126 # the green thread exiting. Fall back to the standard127 # function then.128 t = _fixup_thread(__orig_threading.current_thread())129 else:130 t = active[g_id] = _GreenThread(g)131 132 return t133 134 135currentThread = current_thread136 