"""Implementation of the standard :mod:`thread` module that spawns greenlets... note:: This module is a helper for :mod:`gevent.monkey` and is not intended to be used directly. For spawning greenlets in your applications, prefer higher level constructs like :class:`gevent.Greenlet` class or :func:`gevent.spawn`."""from__future__importabsolute_import__implements__=['allocate_lock','get_ident','exit','LockType','stack_size','start_new_thread','_local',]__imports__=['error']import_threadas__thread__# pylint:disable=import-error__target__='_thread'__imports__+=['TIMEOUT_MAX','allocate','exit_thread','interrupt_main','start_new']# We can't actually produce a value that "may be used# to identify this particular thread system-wide", right?# Even if we could, I imagine people will want to pass this to# non-Python (native) APIs, so we shouldn't mess with it.__imports__.append('get_native_id')# Added to 3.12ifhasattr(__thread__,'daemon_threads_allowed'):__imports__.append('daemon_threads_allowed')error=__thread__.errorfromgevent._compatimportPYPYfromgevent._utilimportcopy_globalsfromgevent.hubimportgetcurrentfromgevent.hubimportGreenletExitfromgevent.hubimportsleepfromgevent._hub_localimportget_hub_if_existsfromgevent.greenletimportGreenletfromgevent.lockimportBoundedSemaphorefromgevent.localimportlocalas_localfromgevent.exceptionsimportLoopExitifhasattr(__thread__,'RLock'):# Added in Python 3.4, backported to PyPy 2.7-7.0__imports__.append("RLock")defget_ident(gr=None):ifgrisNone:gr=getcurrent()returnid(gr)defstart_new_thread(function,args=(),kwargs=None):ifkwargsisnotNone:greenlet=Greenlet.spawn(function,*args,**kwargs)# pylint:disable=not-a-mappingelse:greenlet=Greenlet.spawn(function,*args)returnget_ident(greenlet)
[docs]classLockType(BoundedSemaphore):# Change the ValueError into the appropriate thread error# and any other API changes we need to make to match behaviour_OVER_RELEASE_ERROR=__thread__.errorifPYPY:_OVER_RELEASE_ERROR=RuntimeError_TIMEOUT_MAX=__thread__.TIMEOUT_MAX# pylint:disable=no-member
[docs]defacquire(self,blocking=True,timeout=-1):# This is the Python 3 signature.# On Python 2, Lock.acquire has the signature `Lock.acquire([wait])`# where `wait` is a boolean that cannot be passed by name, only position.# so we're fine to use the Python 3 signature.# Transform the default -1 argument into the None that our# semaphore implementation expects, and raise the same error# the stdlib implementation does.iftimeout==-1:timeout=NoneifnotblockingandtimeoutisnotNone:raiseValueError("can't specify a timeout for a non-blocking call")iftimeoutisnotNone:iftimeout<0:# in C: if(timeout < 0 && timeout != -1)raiseValueError("timeout value must be strictly positive")iftimeout>self._TIMEOUT_MAX:raiseOverflowError('timeout value is too large')try:acquired=BoundedSemaphore.acquire(self,blocking,timeout)exceptLoopExit:# Raised when the semaphore was not trivially ours, and we needed# to block. Some other thread presumably owns the semaphore, and there are no greenlets# running in this thread to switch to. So the best we can do is# release the GIL and try again later.ifblocking:# pragma: no coverraiseacquired=Falseifnotacquiredandnotblockingandgetcurrent()isnotget_hub_if_exists():# Run other callbacks. This makes spin locks works.# We can't do this if we're in the hub, which we could easily be:# printing the repr of a thread checks its tstate_lock, and sometimes we# print reprs in the hub.# See https://github.com/gevent/gevent/issues/1464# By using sleep() instead of self.wait(0), we don't force a trip# around the event loop *unless* we've been running callbacks for# longer than our switch interval.sleep()returnacquired
# Should we implement _is_owned, at least for Python 2? See notes in# monkey.py's patch_existing_locks.allocate_lock=LockTypedefexit():raiseGreenletExitifhasattr(__thread__,'stack_size'):_original_stack_size=__thread__.stack_sizedefstack_size(size=None):ifsizeisNone:return_original_stack_size()ifsize>_original_stack_size():return_original_stack_size(size)# not going to decrease stack_size, because otherwise other# greenlets in this thread will sufferelse:__implements__.remove('stack_size')__imports__=copy_globals(__thread__,globals(),only_names=__imports__,ignore_missing_names=True)__all__=__implements__+__imports____all__.remove('_local')# XXX interrupt_main# XXX _count()