Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

choosereactor.py 8.8KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. ########################################
  2. #
  3. # The MIT License (MIT)
  4. #
  5. # Copyright (c) typedef int GmbH
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy
  8. # of this software and associated documentation files (the "Software'), to deal
  9. # in the Software without restriction, including without limitation the rights
  10. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the Software is
  12. # furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in
  15. # all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. # THE SOFTWARE.
  24. #
  25. ########################################
  26. import sys
  27. import traceback
  28. import txaio
  29. txaio.use_twisted()
  30. from twisted.python import reflect
  31. from twisted.internet.error import ReactorAlreadyInstalledError
  32. __all__ = (
  33. 'install_optimal_reactor',
  34. 'install_reactor',
  35. 'current_reactor_klass'
  36. )
  37. def current_reactor_klass():
  38. """
  39. Return class name of currently installed Twisted reactor or None.
  40. """
  41. if 'twisted.internet.reactor' in sys.modules:
  42. current_reactor = reflect.qual(sys.modules['twisted.internet.reactor'].__class__).split('.')[-1]
  43. else:
  44. current_reactor = None
  45. return current_reactor
  46. def install_optimal_reactor(require_optimal_reactor=True):
  47. """
  48. Try to install the optimal Twisted reactor for this platform:
  49. - Linux: epoll
  50. - BSD/OSX: kqueue
  51. - Windows: iocp
  52. - Other: select
  53. Notes:
  54. - This function exists, because the reactor types selected based on platform
  55. in `twisted.internet.default` are different from here.
  56. - The imports are inlined, because the Twisted code base is notorious for
  57. importing the reactor as a side-effect of merely importing. Hence we postpone
  58. all importing.
  59. See: http://twistedmatrix.com/documents/current/core/howto/choosing-reactor.html#reactor-functionality
  60. :param require_optimal_reactor: If ``True`` and the desired reactor could not be installed,
  61. raise ``ReactorAlreadyInstalledError``, else fallback to another reactor.
  62. :type require_optimal_reactor: bool
  63. :returns: The Twisted reactor in place (`twisted.internet.reactor`).
  64. """
  65. log = txaio.make_logger()
  66. # determine currently installed reactor, if any
  67. #
  68. current_reactor = current_reactor_klass()
  69. # depending on platform, install optimal reactor
  70. #
  71. if 'bsd' in sys.platform or sys.platform.startswith('darwin'):
  72. # *BSD and MacOSX
  73. #
  74. if current_reactor != 'KQueueReactor':
  75. if current_reactor is None:
  76. try:
  77. from twisted.internet import kqreactor
  78. kqreactor.install()
  79. except:
  80. log.warn('Running on *BSD or MacOSX, but cannot install kqueue Twisted reactor: {tb}', tb=traceback.format_exc())
  81. else:
  82. log.debug('Running on *BSD or MacOSX and optimal reactor (kqueue) was installed.')
  83. else:
  84. log.warn('Running on *BSD or MacOSX, but cannot install kqueue Twisted reactor, because another reactor ({klass}) is already installed.', klass=current_reactor)
  85. if require_optimal_reactor:
  86. raise ReactorAlreadyInstalledError()
  87. else:
  88. log.debug('Running on *BSD or MacOSX and optimal reactor (kqueue) already installed.')
  89. elif sys.platform in ['win32']:
  90. # Windows
  91. #
  92. if current_reactor != 'IOCPReactor':
  93. if current_reactor is None:
  94. try:
  95. from twisted.internet.iocpreactor import reactor as iocpreactor
  96. iocpreactor.install()
  97. except:
  98. log.warn('Running on Windows, but cannot install IOCP Twisted reactor: {tb}', tb=traceback.format_exc())
  99. else:
  100. log.debug('Running on Windows and optimal reactor (ICOP) was installed.')
  101. else:
  102. log.warn('Running on Windows, but cannot install IOCP Twisted reactor, because another reactor ({klass}) is already installed.', klass=current_reactor)
  103. if require_optimal_reactor:
  104. raise ReactorAlreadyInstalledError()
  105. else:
  106. log.debug('Running on Windows and optimal reactor (ICOP) already installed.')
  107. elif sys.platform.startswith('linux'):
  108. # Linux
  109. #
  110. if current_reactor != 'EPollReactor':
  111. if current_reactor is None:
  112. try:
  113. from twisted.internet import epollreactor
  114. epollreactor.install()
  115. except:
  116. log.warn('Running on Linux, but cannot install Epoll Twisted reactor: {tb}', tb=traceback.format_exc())
  117. else:
  118. log.debug('Running on Linux and optimal reactor (epoll) was installed.')
  119. else:
  120. log.warn('Running on Linux, but cannot install Epoll Twisted reactor, because another reactor ({klass}) is already installed.', klass=current_reactor)
  121. if require_optimal_reactor:
  122. raise ReactorAlreadyInstalledError()
  123. else:
  124. log.debug('Running on Linux and optimal reactor (epoll) already installed.')
  125. else:
  126. # Other platform
  127. #
  128. if current_reactor != 'SelectReactor':
  129. if current_reactor is None:
  130. try:
  131. from twisted.internet import selectreactor
  132. selectreactor.install()
  133. # from twisted.internet import default as defaultreactor
  134. # defaultreactor.install()
  135. except:
  136. log.warn('Running on "{platform}", but cannot install Select Twisted reactor: {tb}', tb=traceback.format_exc(), platform=sys.platform)
  137. else:
  138. log.debug('Running on "{platform}" and optimal reactor (Select) was installed.', platform=sys.platform)
  139. else:
  140. log.warn('Running on "{platform}", but cannot install Select Twisted reactor, because another reactor ({klass}) is already installed.', klass=current_reactor, platform=sys.platform)
  141. if require_optimal_reactor:
  142. raise ReactorAlreadyInstalledError()
  143. else:
  144. log.debug('Running on "{platform}" and optimal reactor (Select) already installed.', platform=sys.platform)
  145. from twisted.internet import reactor
  146. txaio.config.loop = reactor
  147. return reactor
  148. def install_reactor(explicit_reactor=None, verbose=False, log=None, require_optimal_reactor=True):
  149. """
  150. Install Twisted reactor.
  151. :param explicit_reactor: If provided, install this reactor. Else, install
  152. the optimal reactor.
  153. :type explicit_reactor: obj
  154. :param verbose: If ``True``, log (at level "info") the reactor that is
  155. in place afterwards.
  156. :type verbose: bool
  157. :param log: Explicit logging to this txaio logger object.
  158. :type log: obj
  159. :param require_optimal_reactor: If ``True`` and the desired reactor could not be installed,
  160. raise ``ReactorAlreadyInstalledError``, else fallback to another reactor.
  161. :type require_optimal_reactor: bool
  162. :returns: The Twisted reactor in place (`twisted.internet.reactor`).
  163. """
  164. if not log:
  165. log = txaio.make_logger()
  166. if explicit_reactor:
  167. # install explicitly given reactor
  168. #
  169. from twisted.application.reactors import installReactor
  170. if verbose:
  171. log.info('Trying to install explicitly specified Twisted reactor "{reactor}" ..', reactor=explicit_reactor)
  172. try:
  173. installReactor(explicit_reactor)
  174. except:
  175. log.failure('Could not install Twisted reactor {reactor}\n{log_failure.value}',
  176. reactor=explicit_reactor)
  177. sys.exit(1)
  178. else:
  179. # automatically choose optimal reactor
  180. #
  181. if verbose:
  182. log.info('Automatically choosing optimal Twisted reactor ..')
  183. install_optimal_reactor(require_optimal_reactor)
  184. # now the reactor is installed, import it
  185. from twisted.internet import reactor
  186. txaio.config.loop = reactor
  187. if verbose:
  188. from twisted.python.reflect import qual
  189. log.info('Running on Twisted reactor {reactor}', reactor=qual(reactor.__class__))
  190. return reactor