| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- <?php
- /**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link http://www.workerman.net/
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
- declare(strict_types=1);
- namespace Workerman;
- use Exception;
- use Revolt\EventLoop;
- use RuntimeException;
- use Swoole\Coroutine\System;
- use Throwable;
- use Workerman\Events\EventInterface;
- use Workerman\Events\Revolt;
- use Workerman\Events\Swoole;
- use Workerman\Events\Swow;
- use function function_exists;
- use function is_callable;
- use function pcntl_alarm;
- use function pcntl_signal;
- use function time;
- use const PHP_INT_MAX;
- use const SIGALRM;
- /**
- * Timer.
- */
- class Timer
- {
- /**
- * Tasks that based on ALARM signal.
- * [
- * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
- * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
- * ..
- * ]
- *
- * @var array
- */
- protected static array $tasks = [];
- /**
- * Event
- *
- * @var ?EventInterface
- */
- protected static ?EventInterface $event = null;
- /**
- * Timer id
- *
- * @var int
- */
- protected static int $timerId = 0;
- /**
- * Timer status
- * [
- * timer_id1 => bool,
- * timer_id2 => bool,
- * ....................,
- * ]
- *
- * @var array
- */
- protected static array $status = [];
- /**
- * Init.
- *
- * @param EventInterface|null $event
- * @return void
- */
- public static function init(EventInterface $event = null)
- {
- if ($event) {
- self::$event = $event;
- return;
- }
- if (function_exists('pcntl_signal')) {
- pcntl_signal(SIGALRM, ['\Workerman\Timer', 'signalHandle'], false);
- }
- }
- /**
- * ALARM signal handler.
- *
- * @return void
- */
- public static function signalHandle()
- {
- if (!self::$event) {
- pcntl_alarm(1);
- self::tick();
- }
- }
- /**
- * Add a timer.
- *
- * @param float $timeInterval
- * @param callable $func
- * @param mixed|array $args
- * @param bool $persistent
- * @return int
- */
- public static function add(float $timeInterval, callable $func, null|array $args = [], bool $persistent = true): int
- {
- if ($timeInterval < 0) {
- throw new RuntimeException('$timeInterval can not less than 0');
- }
- if ($args === null) {
- $args = [];
- }
- if (self::$event) {
- return $persistent ? self::$event->repeat($timeInterval, $func, $args) : self::$event->delay($timeInterval, $func, $args);
- }
- // If not workerman runtime just return.
- if (!Worker::getAllWorkers()) {
- throw new RuntimeException('Timer can only be used in workerman running environment');
- }
- if (empty(self::$tasks)) {
- pcntl_alarm(1);
- }
- $runTime = time() + $timeInterval;
- if (!isset(self::$tasks[$runTime])) {
- self::$tasks[$runTime] = [];
- }
- self::$timerId = self::$timerId == PHP_INT_MAX ? 1 : ++self::$timerId;
- self::$status[self::$timerId] = true;
- self::$tasks[$runTime][self::$timerId] = [$func, (array)$args, $persistent, $timeInterval];
- return self::$timerId;
- }
- /**
- * Coroutine sleep.
- *
- * @param float $delay
- * @return void
- */
- public static function sleep(float $delay)
- {
- switch (Worker::$eventLoopClass) {
- // Fiber
- case Revolt::class:
- $suspension = EventLoop::getSuspension();
- static::add($delay, function () use ($suspension) {
- $suspension->resume();
- }, null, false);
- $suspension->suspend();
- return;
- // Swoole
- case Swoole::class:
- System::sleep($delay);
- return;
- // Swow
- case Swow::class:
- usleep($delay * 1000 * 1000);
- return;
- }
- throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer require revolt/event-loop" and restart workerman');
- }
- /**
- * Tick.
- *
- * @return void
- */
- public static function tick()
- {
- if (empty(self::$tasks)) {
- pcntl_alarm(0);
- return;
- }
- $timeNow = time();
- foreach (self::$tasks as $runTime => $taskData) {
- if ($timeNow >= $runTime) {
- foreach ($taskData as $index => $oneTask) {
- $taskFunc = $oneTask[0];
- $taskArgs = $oneTask[1];
- $persistent = $oneTask[2];
- $timeInterval = $oneTask[3];
- try {
- $taskFunc(...$taskArgs);
- } catch (Throwable $e) {
- Worker::safeEcho((string)$e);
- }
- if ($persistent && !empty(self::$status[$index])) {
- $newRunTime = time() + $timeInterval;
- if (!isset(self::$tasks[$newRunTime])) self::$tasks[$newRunTime] = [];
- self::$tasks[$newRunTime][$index] = [$taskFunc, (array)$taskArgs, $persistent, $timeInterval];
- }
- }
- unset(self::$tasks[$runTime]);
- }
- }
- }
- /**
- * Remove a timer.
- *
- * @param int $timerId
- * @return bool
- */
- public static function del(int $timerId): bool
- {
- if (self::$event) {
- return self::$event->offDelay($timerId);
- }
- foreach (self::$tasks as $runTime => $taskData) {
- if (array_key_exists($timerId, $taskData)) {
- unset(self::$tasks[$runTime][$timerId]);
- }
- }
- if (array_key_exists($timerId, self::$status)) {
- unset(self::$status[$timerId]);
- }
- return true;
- }
- /**
- * Remove all timers.
- *
- * @return void
- */
- public static function delAll()
- {
- self::$tasks = self::$status = [];
- if (function_exists('pcntl_alarm')) {
- pcntl_alarm(0);
- }
- if (self::$event) {
- self::$event->deleteAllTimer();
- }
- }
- }
|