PocketMine-MP 5.15.1 git-5ef247620a7c6301a849b54e5ef1009217729fc8
SleeperHandler.php
1<?php
2
3/*
4 * This file is part of Snooze <https://github.com/pmmp/Snooze>
5 * Copyright (c) 2018-2023 PMMP Team
6 *
7 * Snooze is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13declare(strict_types=1);
14
15namespace pocketmine\snooze;
16
17use pmmp\thread\ThreadSafeArray;
18use function count;
19use function microtime;
20
30 private readonly ThreadSafeArray $sharedObject;
31
36 private array $handlers = [];
37
38 private int $nextSleeperId = 0;
39
40 public function __construct(){
41 $this->sharedObject = new ThreadSafeArray();
42 }
43
48 public function addNotifier(\Closure $handler) : SleeperHandlerEntry{
49 $id = $this->nextSleeperId++;
50 $notifier = new SleeperHandlerEntry($this->sharedObject, $id);
51 $this->handlers[$id] = $handler;
52 return $notifier;
53 }
54
61 public function removeNotifier(int $notifierId) : void{
62 unset($this->handlers[$notifierId]);
63 }
64
65 private function sleep(int $timeout) : void{
66 $this->sharedObject->synchronized(function() use ($timeout) : void{
67 if($this->sharedObject->count() === 0){
68 $this->sharedObject->wait($timeout);
69 }
70 });
71 }
72
77 public function sleepUntil(float $unixTime) : void{
78 while(true){
79 $this->processNotifications();
80
81 $sleepTime = (int) (($unixTime - microtime(true)) * 1000000);
82 if($sleepTime > 0){
83 $this->sleep($sleepTime);
84 }else{
85 break;
86 }
87 }
88 }
89
94 public function sleepUntilNotification() : void{
95 $this->sleep(0);
96 $this->processNotifications();
97 }
98
102 public function processNotifications() : void{
103 while(true){
104 $notifierIds = $this->sharedObject->synchronized(function() : array{
105 $notifierIds = [];
106 foreach($this->sharedObject as $notifierId => $_){
107 $notifierIds[$notifierId] = $notifierId;
108 unset($this->sharedObject[$notifierId]);
109 }
110 return $notifierIds;
111 });
112 if(count($notifierIds) === 0){
113 break;
114 }
115 foreach($notifierIds as $notifierId){
116 if(!isset($this->handlers[$notifierId])){
117 //a previously-removed notifier might still be sending notifications; ignore them
118 continue;
119 }
120 $this->handlers[$notifierId]();
121 }
122 }
123 }
124}