|
- """Implements the standard thread module, using greenthreads."""
- from six.moves import _thread as __thread
- import six
- from eventlet.support import greenlets as greenlet
- from eventlet import greenthread
- from eventlet.semaphore import Semaphore as LockType
- import sys
-
-
- __patched__ = ['get_ident', 'start_new_thread', 'start_new', 'allocate_lock',
- 'allocate', 'exit', 'interrupt_main', 'stack_size', '_local',
- 'LockType', '_count']
-
- error = __thread.error
- __threadcount = 0
-
-
- if six.PY3:
- def _set_sentinel():
- # TODO this is a dummy code, reimplementing this may be needed:
- # https://hg.python.org/cpython/file/b5e9bc4352e1/Modules/_threadmodule.c#l1203
- return allocate_lock()
-
- TIMEOUT_MAX = __thread.TIMEOUT_MAX
-
-
- def _count():
- return __threadcount
-
-
- def get_ident(gr=None):
- if gr is None:
- return id(greenlet.getcurrent())
- else:
- return id(gr)
-
-
- def __thread_body(func, args, kwargs):
- global __threadcount
- __threadcount += 1
- try:
- func(*args, **kwargs)
- finally:
- __threadcount -= 1
-
-
- def start_new_thread(function, args=(), kwargs=None):
- if (sys.version_info >= (3, 4)
- and getattr(function, '__module__', '') == 'threading'
- and hasattr(function, '__self__')):
- # Since Python 3.4, threading.Thread uses an internal lock
- # automatically released when the python thread state is deleted.
- # With monkey patching, eventlet uses green threads without python
- # thread state, so the lock is not automatically released.
- #
- # Wrap _bootstrap_inner() to release explicitly the thread state lock
- # when the thread completes.
- thread = function.__self__
- bootstrap_inner = thread._bootstrap_inner
-
- def wrap_bootstrap_inner():
- try:
- bootstrap_inner()
- finally:
- # The lock can be cleared (ex: by a fork())
- if thread._tstate_lock is not None:
- thread._tstate_lock.release()
-
- thread._bootstrap_inner = wrap_bootstrap_inner
-
- kwargs = kwargs or {}
- g = greenthread.spawn_n(__thread_body, function, args, kwargs)
- return get_ident(g)
-
-
- start_new = start_new_thread
-
-
- def allocate_lock(*a):
- return LockType(1)
-
-
- allocate = allocate_lock
-
-
- def exit():
- raise greenlet.GreenletExit
-
-
- exit_thread = __thread.exit_thread
-
-
- def interrupt_main():
- curr = greenlet.getcurrent()
- if curr.parent and not curr.parent.dead:
- curr.parent.throw(KeyboardInterrupt())
- else:
- raise KeyboardInterrupt()
-
-
- if hasattr(__thread, 'stack_size'):
- __original_stack_size__ = __thread.stack_size
-
- def stack_size(size=None):
- if size is None:
- return __original_stack_size__()
- if size > __original_stack_size__():
- return __original_stack_size__(size)
- else:
- pass
- # not going to decrease stack_size, because otherwise other greenlets in
- # this thread will suffer
-
- from eventlet.corolocal import local as _local
|