1# -*- encoding: utf-8 -*- 2"""This files exposes non-gevent Python original functions.""" 3import threading 4 5import attr 6import six 7 8from ddtrace.internal import compat 9from ddtrace.internal import forksafe 10 11 12try: 13 import gevent.monkey 14except ImportError: 15 16 def get_original(module, func): 17 return getattr(__import__(module), func) 18 19 def is_module_patched(module): 20 return False 21 22 23else: 24 get_original = gevent.monkey.get_original 25 is_module_patched = gevent.monkey.is_module_patched 26 27 28sleep = get_original("time", "sleep") 29 30try: 31 # Python ≥ 3.8 32 threading_get_native_id = get_original("threading", "get_native_id") 33except AttributeError: 34 threading_get_native_id = None 35 36start_new_thread = get_original(six.moves._thread.__name__, "start_new_thread") 37thread_get_ident = get_original(six.moves._thread.__name__, "get_ident") 38Thread = get_original("threading", "Thread") 39Lock = get_original("threading", "Lock") 40 41 42if is_module_patched("threading"): 43 44 @attr.s 45 class DoubleLock(object): 46 """A lock that prevent concurrency from a gevent coroutine and from a threading.Thread at the same time.""" 47 48 # This is a gevent-patched threading.Lock (= a gevent Lock) 49 _lock = attr.ib(factory=forksafe.Lock, init=False, repr=False) 50 # This is a unpatched threading.Lock (= a real threading.Lock) 51 _thread_lock = attr.ib(factory=lambda: forksafe.ResetObject(Lock), init=False, repr=False) 52 53 def acquire(self): 54 # type: () -> None 55 # You cannot acquire a gevent-lock from another thread if it has been acquired already: 56 # make sure we exclude the gevent-lock from being acquire by another thread by using a thread-lock first. 57 self._thread_lock.acquire() 58 self._lock.acquire() 59 60 def release(self): 61 # type: () -> None 62 self._lock.release() 63 self._thread_lock.release() 64 65 def __enter__(self): 66 # type: () -> DoubleLock 67 self.acquire() 68 return self 69 70 def __exit__(self, exc_type, exc_val, exc_tb): 71 self.release() 72 73 74else: 75 DoubleLock = threading.Lock # type: ignore[misc,assignment] 76 77 78if is_module_patched("threading"): 79 # NOTE: bold assumption: this module is always imported by the MainThread. 80 # The python `threading` module makes that assumption and it's beautiful we're going to do the same. 81 # We don't have the choice has we can't access the original MainThread 82 main_thread_id = thread_get_ident() 83else: 84 main_thread_id = compat.main_thread.ident 85