Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

191 строка
5.9KB

  1. import importlib
  2. import inspect
  3. import os
  4. import warnings
  5. from eventlet import patcher
  6. from eventlet.support import greenlets as greenlet
  7. import six
  8. __all__ = ["use_hub", "get_hub", "get_default_hub", "trampoline"]
  9. threading = patcher.original('threading')
  10. _threadlocal = threading.local()
  11. # order is important, get_default_hub returns first available from here
  12. builtin_hub_names = ('epolls', 'kqueue', 'poll', 'selects')
  13. builtin_hub_modules = tuple(importlib.import_module('eventlet.hubs.' + name) for name in builtin_hub_names)
  14. class HubError(Exception):
  15. pass
  16. def get_default_hub():
  17. """Select the default hub implementation based on what multiplexing
  18. libraries are installed. The order that the hubs are tried is:
  19. * epoll
  20. * kqueue
  21. * poll
  22. * select
  23. It won't automatically select the pyevent hub, because it's not
  24. python-thread-safe.
  25. .. include:: ../doc/common.txt
  26. .. note :: |internal|
  27. """
  28. for mod in builtin_hub_modules:
  29. if mod.is_available():
  30. return mod
  31. raise HubError('no built-in hubs are available: {}'.format(builtin_hub_modules))
  32. def use_hub(mod=None):
  33. """Use the module *mod*, containing a class called Hub, as the
  34. event hub. Usually not required; the default hub is usually fine.
  35. `mod` can be an actual hub class, a module, a string, or None.
  36. If `mod` is a class, use it directly.
  37. If `mod` is a module, use `module.Hub` class
  38. If `mod` is a string and contains either '.' or ':'
  39. then `use_hub` uses 'package.subpackage.module:Class' convention,
  40. otherwise imports `eventlet.hubs.mod`.
  41. If `mod` is None, `use_hub` uses the default hub.
  42. Only call use_hub during application initialization,
  43. because it resets the hub's state and any existing
  44. timers or listeners will never be resumed.
  45. These two threadlocal attributes are not part of Eventlet public API:
  46. - `threadlocal.Hub` (capital H) is hub constructor, used when no hub is currently active
  47. - `threadlocal.hub` (lowercase h) is active hub instance
  48. """
  49. if mod is None:
  50. mod = os.environ.get('EVENTLET_HUB', None)
  51. if mod is None:
  52. mod = get_default_hub()
  53. if hasattr(_threadlocal, 'hub'):
  54. del _threadlocal.hub
  55. classname = ''
  56. if isinstance(mod, six.string_types):
  57. assert mod.strip(), "Need to specify a hub"
  58. if '.' in mod or ':' in mod:
  59. modulename, _, classname = mod.strip().partition(':')
  60. else:
  61. modulename = 'eventlet.hubs.' + mod
  62. mod = importlib.import_module(modulename)
  63. if hasattr(mod, 'is_available'):
  64. if not mod.is_available():
  65. raise Exception('selected hub is not available on this system mod={}'.format(mod))
  66. else:
  67. msg = '''Please provide `is_available()` function in your custom Eventlet hub {mod}.
  68. It must return bool: whether hub supports current platform. See eventlet/hubs/{{epoll,kqueue}} for example.
  69. '''.format(mod=mod)
  70. warnings.warn(msg, DeprecationWarning, stacklevel=3)
  71. hubclass = mod
  72. if not inspect.isclass(mod):
  73. hubclass = getattr(mod, classname or 'Hub')
  74. _threadlocal.Hub = hubclass
  75. def get_hub():
  76. """Get the current event hub singleton object.
  77. .. note :: |internal|
  78. """
  79. try:
  80. hub = _threadlocal.hub
  81. except AttributeError:
  82. try:
  83. _threadlocal.Hub
  84. except AttributeError:
  85. use_hub()
  86. hub = _threadlocal.hub = _threadlocal.Hub()
  87. return hub
  88. # Lame middle file import because complex dependencies in import graph
  89. from eventlet import timeout
  90. def trampoline(fd, read=None, write=None, timeout=None,
  91. timeout_exc=timeout.Timeout,
  92. mark_as_closed=None):
  93. """Suspend the current coroutine until the given socket object or file
  94. descriptor is ready to *read*, ready to *write*, or the specified
  95. *timeout* elapses, depending on arguments specified.
  96. To wait for *fd* to be ready to read, pass *read* ``=True``; ready to
  97. write, pass *write* ``=True``. To specify a timeout, pass the *timeout*
  98. argument in seconds.
  99. If the specified *timeout* elapses before the socket is ready to read or
  100. write, *timeout_exc* will be raised instead of ``trampoline()``
  101. returning normally.
  102. .. note :: |internal|
  103. """
  104. t = None
  105. hub = get_hub()
  106. current = greenlet.getcurrent()
  107. assert hub.greenlet is not current, 'do not call blocking functions from the mainloop'
  108. assert not (
  109. read and write), 'not allowed to trampoline for reading and writing'
  110. try:
  111. fileno = fd.fileno()
  112. except AttributeError:
  113. fileno = fd
  114. if timeout is not None:
  115. def _timeout(exc):
  116. # This is only useful to insert debugging
  117. current.throw(exc)
  118. t = hub.schedule_call_global(timeout, _timeout, timeout_exc)
  119. try:
  120. if read:
  121. listener = hub.add(hub.READ, fileno, current.switch, current.throw, mark_as_closed)
  122. elif write:
  123. listener = hub.add(hub.WRITE, fileno, current.switch, current.throw, mark_as_closed)
  124. try:
  125. return hub.switch()
  126. finally:
  127. hub.remove(listener)
  128. finally:
  129. if t is not None:
  130. t.cancel()
  131. def notify_close(fd):
  132. """
  133. A particular file descriptor has been explicitly closed. Register for any
  134. waiting listeners to be notified on the next run loop.
  135. """
  136. hub = get_hub()
  137. hub.notify_close(fd)
  138. def notify_opened(fd):
  139. """
  140. Some file descriptors may be closed 'silently' - that is, by the garbage
  141. collector, by an external library, etc. When the OS returns a file descriptor
  142. from an open call (or something similar), this may be the only indication we
  143. have that the FD has been closed and then recycled.
  144. We let the hub know that the old file descriptor is dead; any stuck listeners
  145. will be disabled and notified in turn.
  146. """
  147. hub = get_hub()
  148. hub.mark_as_reopened(fd)
  149. class IOClosed(IOError):
  150. pass