/vendor/react/event-loop/React/EventLoop/StreamSelectLoop.php

https://bitbucket.org/nbravo777/repo_ratchet · PHP · 170 lines · 133 code · 33 blank · 4 comment · 15 complexity · 3b586bc063b612a1079ffb080a98b000 MD5 · raw file

  1. <?php
  2. namespace React\EventLoop;
  3. use React\EventLoop\Timer\Timers;
  4. class StreamSelectLoop implements LoopInterface
  5. {
  6. const QUANTUM_INTERVAL = 1000000;
  7. private $timers;
  8. private $running = false;
  9. private $readStreams = array();
  10. private $readListeners = array();
  11. private $writeStreams = array();
  12. private $writeListeners = array();
  13. public function __construct()
  14. {
  15. $this->timers = new Timers($this);
  16. }
  17. public function addReadStream($stream, $listener)
  18. {
  19. $id = (int) $stream;
  20. if (!isset($this->readStreams[$id])) {
  21. $this->readStreams[$id] = $stream;
  22. $this->readListeners[$id] = $listener;
  23. }
  24. }
  25. public function addWriteStream($stream, $listener)
  26. {
  27. $id = (int) $stream;
  28. if (!isset($this->writeStreams[$id])) {
  29. $this->writeStreams[$id] = $stream;
  30. $this->writeListeners[$id] = $listener;
  31. }
  32. }
  33. public function removeReadStream($stream)
  34. {
  35. $id = (int) $stream;
  36. unset(
  37. $this->readStreams[$id],
  38. $this->readListeners[$id]
  39. );
  40. }
  41. public function removeWriteStream($stream)
  42. {
  43. $id = (int) $stream;
  44. unset(
  45. $this->writeStreams[$id],
  46. $this->writeListeners[$id]
  47. );
  48. }
  49. public function removeStream($stream)
  50. {
  51. $this->removeReadStream($stream);
  52. $this->removeWriteStream($stream);
  53. }
  54. public function addTimer($interval, $callback)
  55. {
  56. return $this->timers->add($interval, $callback);
  57. }
  58. public function addPeriodicTimer($interval, $callback)
  59. {
  60. return $this->timers->add($interval, $callback, true);
  61. }
  62. public function cancelTimer($signature)
  63. {
  64. $this->timers->cancel($signature);
  65. }
  66. protected function getNextEventTimeInMicroSeconds()
  67. {
  68. $nextEvent = $this->timers->getFirst();
  69. if (null === $nextEvent) {
  70. return self::QUANTUM_INTERVAL;
  71. }
  72. $currentTime = microtime(true);
  73. if ($nextEvent > $currentTime) {
  74. return ($nextEvent - $currentTime) * 1000000;
  75. }
  76. return 0;
  77. }
  78. protected function sleepOnPendingTimers()
  79. {
  80. if ($this->timers->isEmpty()) {
  81. $this->running = false;
  82. } else {
  83. // We use usleep() instead of stream_select() to emulate timeouts
  84. // since the latter fails when there are no streams registered for
  85. // read / write events. Blame PHP for us needing this hack.
  86. usleep($this->getNextEventTimeInMicroSeconds());
  87. }
  88. }
  89. protected function runStreamSelect()
  90. {
  91. $read = $this->readStreams ?: null;
  92. $write = $this->writeStreams ?: null;
  93. $except = null;
  94. if (!$read && !$write) {
  95. $this->sleepOnPendingTimers();
  96. return;
  97. }
  98. if (stream_select($read, $write, $except, 0, $this->getNextEventTimeInMicroSeconds()) > 0) {
  99. if ($read) {
  100. foreach ($read as $stream) {
  101. $listener = $this->readListeners[(int) $stream];
  102. if (call_user_func($listener, $stream, $this) === false) {
  103. $this->removeReadStream($stream);
  104. }
  105. }
  106. }
  107. if ($write) {
  108. foreach ($write as $stream) {
  109. if (!isset($this->writeListeners[(int) $stream])) {
  110. continue;
  111. }
  112. $listener = $this->writeListeners[(int) $stream];
  113. if (call_user_func($listener, $stream, $this) === false) {
  114. $this->removeWriteStream($stream);
  115. }
  116. }
  117. }
  118. }
  119. }
  120. public function tick()
  121. {
  122. $this->timers->tick();
  123. $this->runStreamSelect();
  124. return $this->running;
  125. }
  126. public function run()
  127. {
  128. $this->running = true;
  129. while ($this->tick()) {
  130. // NOOP
  131. }
  132. }
  133. public function stop()
  134. {
  135. $this->running = false;
  136. }
  137. }