thread.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. """
  2. Implementation of the standard :mod:`thread` module that spawns greenlets.
  3. .. note::
  4. This module is a helper for :mod:`gevent.monkey` and is not
  5. intended to be used directly. For spawning greenlets in your
  6. applications, prefer higher level constructs like
  7. :class:`gevent.Greenlet` class or :func:`gevent.spawn`.
  8. """
  9. from __future__ import absolute_import
  10. import sys
  11. __implements__ = ['allocate_lock',
  12. 'get_ident',
  13. 'exit',
  14. 'LockType',
  15. 'stack_size',
  16. 'start_new_thread',
  17. '_local']
  18. __imports__ = ['error']
  19. if sys.version_info[0] <= 2:
  20. import thread as __thread__ # pylint:disable=import-error
  21. else:
  22. import _thread as __thread__ # pylint:disable=import-error
  23. __target__ = '_thread'
  24. __imports__ += ['RLock',
  25. 'TIMEOUT_MAX',
  26. 'allocate',
  27. 'exit_thread',
  28. 'interrupt_main',
  29. 'start_new']
  30. error = __thread__.error
  31. from gevent._compat import PY3
  32. from gevent._compat import PYPY
  33. from gevent._util import copy_globals
  34. from gevent.hub import getcurrent, GreenletExit
  35. from gevent.greenlet import Greenlet
  36. from gevent.lock import BoundedSemaphore
  37. from gevent.local import local as _local
  38. def get_ident(gr=None):
  39. if gr is None:
  40. gr = getcurrent()
  41. return id(gr)
  42. def start_new_thread(function, args=(), kwargs=None):
  43. if kwargs is not None:
  44. greenlet = Greenlet.spawn(function, *args, **kwargs)
  45. else:
  46. greenlet = Greenlet.spawn(function, *args)
  47. return get_ident(greenlet)
  48. class LockType(BoundedSemaphore):
  49. # Change the ValueError into the appropriate thread error
  50. # and any other API changes we need to make to match behaviour
  51. _OVER_RELEASE_ERROR = __thread__.error
  52. if PYPY and PY3:
  53. _OVER_RELEASE_ERROR = RuntimeError
  54. if PY3:
  55. _TIMEOUT_MAX = __thread__.TIMEOUT_MAX # python 2: pylint:disable=no-member
  56. def acquire(self, blocking=True, timeout=-1):
  57. # Transform the default -1 argument into the None that our
  58. # semaphore implementation expects, and raise the same error
  59. # the stdlib implementation does.
  60. if timeout == -1:
  61. timeout = None
  62. if not blocking and timeout is not None:
  63. raise ValueError("can't specify a timeout for a non-blocking call")
  64. if timeout is not None:
  65. if timeout < 0:
  66. # in C: if(timeout < 0 && timeout != -1)
  67. raise ValueError("timeout value must be strictly positive")
  68. if timeout > self._TIMEOUT_MAX:
  69. raise OverflowError('timeout value is too large')
  70. return BoundedSemaphore.acquire(self, blocking, timeout)
  71. allocate_lock = LockType
  72. def exit():
  73. raise GreenletExit
  74. if hasattr(__thread__, 'stack_size'):
  75. _original_stack_size = __thread__.stack_size
  76. def stack_size(size=None):
  77. if size is None:
  78. return _original_stack_size()
  79. if size > _original_stack_size():
  80. return _original_stack_size(size)
  81. else:
  82. pass
  83. # not going to decrease stack_size, because otherwise other greenlets in this thread will suffer
  84. else:
  85. __implements__.remove('stack_size')
  86. __imports__ = copy_globals(__thread__, globals(),
  87. only_names=__imports__,
  88. ignore_missing_names=True)
  89. __all__ = __implements__ + __imports__
  90. __all__.remove('_local')
  91. # XXX interrupt_main
  92. # XXX _count()