You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.0KB

  1. """Implements the standard thread module, using greenthreads."""
  2. from six.moves import _thread as __thread
  3. import six
  4. from eventlet.support import greenlets as greenlet
  5. from eventlet import greenthread
  6. from eventlet.semaphore import Semaphore as LockType
  7. import sys
  8. __patched__ = ['get_ident', 'start_new_thread', 'start_new', 'allocate_lock',
  9. 'allocate', 'exit', 'interrupt_main', 'stack_size', '_local',
  10. 'LockType', '_count']
  11. error = __thread.error
  12. __threadcount = 0
  13. if six.PY3:
  14. def _set_sentinel():
  15. # TODO this is a dummy code, reimplementing this may be needed:
  16. # https://hg.python.org/cpython/file/b5e9bc4352e1/Modules/_threadmodule.c#l1203
  17. return allocate_lock()
  18. TIMEOUT_MAX = __thread.TIMEOUT_MAX
  19. def _count():
  20. return __threadcount
  21. def get_ident(gr=None):
  22. if gr is None:
  23. return id(greenlet.getcurrent())
  24. else:
  25. return id(gr)
  26. def __thread_body(func, args, kwargs):
  27. global __threadcount
  28. __threadcount += 1
  29. try:
  30. func(*args, **kwargs)
  31. finally:
  32. __threadcount -= 1
  33. def start_new_thread(function, args=(), kwargs=None):
  34. if (sys.version_info >= (3, 4)
  35. and getattr(function, '__module__', '') == 'threading'
  36. and hasattr(function, '__self__')):
  37. # Since Python 3.4, threading.Thread uses an internal lock
  38. # automatically released when the python thread state is deleted.
  39. # With monkey patching, eventlet uses green threads without python
  40. # thread state, so the lock is not automatically released.
  41. #
  42. # Wrap _bootstrap_inner() to release explicitly the thread state lock
  43. # when the thread completes.
  44. thread = function.__self__
  45. bootstrap_inner = thread._bootstrap_inner
  46. def wrap_bootstrap_inner():
  47. try:
  48. bootstrap_inner()
  49. finally:
  50. # The lock can be cleared (ex: by a fork())
  51. if thread._tstate_lock is not None:
  52. thread._tstate_lock.release()
  53. thread._bootstrap_inner = wrap_bootstrap_inner
  54. kwargs = kwargs or {}
  55. g = greenthread.spawn_n(__thread_body, function, args, kwargs)
  56. return get_ident(g)
  57. start_new = start_new_thread
  58. def allocate_lock(*a):
  59. return LockType(1)
  60. allocate = allocate_lock
  61. def exit():
  62. raise greenlet.GreenletExit
  63. exit_thread = __thread.exit_thread
  64. def interrupt_main():
  65. curr = greenlet.getcurrent()
  66. if curr.parent and not curr.parent.dead:
  67. curr.parent.throw(KeyboardInterrupt())
  68. else:
  69. raise KeyboardInterrupt()
  70. if hasattr(__thread, 'stack_size'):
  71. __original_stack_size__ = __thread.stack_size
  72. def stack_size(size=None):
  73. if size is None:
  74. return __original_stack_size__()
  75. if size > __original_stack_size__():
  76. return __original_stack_size__(size)
  77. else:
  78. pass
  79. # not going to decrease stack_size, because otherwise other greenlets in
  80. # this thread will suffer
  81. from eventlet.corolocal import local as _local