Timer.class.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. /**
  3. * This file is part of workerman.
  4. *
  5. * Licensed under The MIT License
  6. * For full copyright and license information, please see the MIT-LICENSE.txt
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @author walkor<walkor@workerman.net>
  10. * @copyright walkor<walkor@workerman.net>
  11. * @link http://www.workerman.net/
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Workerman;
  15. use Workerman\Events\EventInterface;
  16. use Workerman\Worker;
  17. use \Exception;
  18. /**
  19. * Timer.
  20. *
  21. * example:
  22. * Workerman\Timer::add($time_interval, callback, array($arg1, $arg2..));
  23. */
  24. class Timer
  25. {
  26. /**
  27. * Tasks that based on ALARM signal.
  28. * [
  29. * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
  30. * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
  31. * ..
  32. * ]
  33. *
  34. * @var array
  35. */
  36. protected static $_tasks = array();
  37. /**
  38. * event
  39. *
  40. * @var EventInterface
  41. */
  42. protected static $_event = null;
  43. /**
  44. * timer id
  45. *
  46. * @var int
  47. */
  48. protected static $_timerId = 0;
  49. /**
  50. * timer status
  51. * [
  52. * timer_id1 => bool,
  53. * timer_id2 => bool,
  54. * ....................,
  55. * ]
  56. *
  57. * @var array
  58. */
  59. protected static $_status = array();
  60. /**
  61. * Init.
  62. *
  63. * @param EventInterface $event
  64. * @return void
  65. */
  66. public static function init($event = null)
  67. {
  68. if ($event) {
  69. self::$_event = $event;
  70. return;
  71. }
  72. if (\function_exists('pcntl_signal')) {
  73. \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false);
  74. }
  75. }
  76. /**
  77. * ALARM signal handler.
  78. *
  79. * @return void
  80. */
  81. public static function signalHandle()
  82. {
  83. if (!self::$_event) {
  84. \pcntl_alarm(1);
  85. self::tick();
  86. }
  87. }
  88. /**
  89. * Add a timer.
  90. *
  91. * @param float $time_interval
  92. * @param callable $func
  93. * @param mixed $args
  94. * @param bool $persistent
  95. * @return int|bool
  96. */
  97. public static function add($time_interval, $func, $args = array(), $persistent = true)
  98. {
  99. if ($time_interval <= 0) {
  100. Worker::safeEcho(new Exception("bad time_interval"));
  101. return false;
  102. }
  103. if ($args === null) {
  104. $args = array();
  105. }
  106. if (self::$_event) {
  107. return self::$_event->add($time_interval,
  108. $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args);
  109. }
  110. // If not workerman runtime just return.
  111. if (!Worker::getAllWorkers()) {
  112. return;
  113. }
  114. if (!\is_callable($func)) {
  115. Worker::safeEcho(new Exception("not callable"));
  116. return false;
  117. }
  118. if (empty(self::$_tasks)) {
  119. \pcntl_alarm(1);
  120. }
  121. $run_time = \time() + $time_interval;
  122. if (!isset(self::$_tasks[$run_time])) {
  123. self::$_tasks[$run_time] = array();
  124. }
  125. self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId;
  126. self::$_status[self::$_timerId] = true;
  127. self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval);
  128. return self::$_timerId;
  129. }
  130. /**
  131. * Tick.
  132. *
  133. * @return void
  134. */
  135. public static function tick()
  136. {
  137. if (empty(self::$_tasks)) {
  138. \pcntl_alarm(0);
  139. return;
  140. }
  141. $time_now = \time();
  142. foreach (self::$_tasks as $run_time => $task_data) {
  143. if ($time_now >= $run_time) {
  144. foreach ($task_data as $index => $one_task) {
  145. $task_func = $one_task[0];
  146. $task_args = $one_task[1];
  147. $persistent = $one_task[2];
  148. $time_interval = $one_task[3];
  149. try {
  150. \call_user_func_array($task_func, $task_args);
  151. } catch (\Exception $e) {
  152. Worker::safeEcho($e);
  153. }
  154. if($persistent && !empty(self::$_status[$index])) {
  155. $new_run_time = \time() + $time_interval;
  156. if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array();
  157. self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval);
  158. }
  159. }
  160. unset(self::$_tasks[$run_time]);
  161. }
  162. }
  163. }
  164. /**
  165. * Remove a timer.
  166. *
  167. * @param mixed $timer_id
  168. * @return bool
  169. */
  170. public static function del($timer_id)
  171. {
  172. if (self::$_event) {
  173. return self::$_event->del($timer_id, EventInterface::EV_TIMER);
  174. }
  175. foreach(self::$_tasks as $run_time => $task_data)
  176. {
  177. if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]);
  178. }
  179. if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]);
  180. return true;
  181. }
  182. /**
  183. * Remove all timers.
  184. *
  185. * @return void
  186. */
  187. public static function delAll()
  188. {
  189. self::$_tasks = self::$_status = array();
  190. \pcntl_alarm(0);
  191. if (self::$_event) {
  192. self::$_event->clearAllTimer();
  193. }
  194. }
  195. }