2017-01-05 12:57:35 -06:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Amp\Loop;
|
|
|
|
|
|
|
|
use Amp\Loop\Internal\Watcher;
|
|
|
|
|
|
|
|
class EventLoop extends Loop {
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var \EventBase */
|
2017-01-05 12:57:35 -06:00
|
|
|
private $handle;
|
|
|
|
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var \Event[] */
|
2017-01-05 12:57:35 -06:00
|
|
|
private $events = [];
|
|
|
|
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var callable */
|
2017-01-05 12:57:35 -06:00
|
|
|
private $ioCallback;
|
|
|
|
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var callable */
|
2017-01-05 12:57:35 -06:00
|
|
|
private $timerCallback;
|
|
|
|
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var callable */
|
2017-01-05 12:57:35 -06:00
|
|
|
private $signalCallback;
|
2017-01-05 17:32:03 -06:00
|
|
|
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var \Event[] */
|
2017-01-05 17:32:03 -06:00
|
|
|
private $signals = [];
|
|
|
|
|
2017-02-16 22:36:32 -06:00
|
|
|
/** @var \Event[]|null */
|
2017-01-05 17:32:03 -06:00
|
|
|
private static $activeSignals;
|
2017-01-05 12:57:35 -06:00
|
|
|
|
|
|
|
public static function supported() {
|
|
|
|
return \extension_loaded("event");
|
|
|
|
}
|
|
|
|
|
|
|
|
public function __construct() {
|
|
|
|
$this->handle = new \EventBase;
|
2017-01-05 17:32:03 -06:00
|
|
|
|
|
|
|
if (self::$activeSignals === null) {
|
|
|
|
self::$activeSignals = &$this->signals;
|
|
|
|
}
|
|
|
|
|
2017-01-05 12:57:35 -06:00
|
|
|
$this->ioCallback = function ($resource, $what, Watcher $watcher) {
|
|
|
|
$callback = $watcher->callback;
|
|
|
|
$callback($watcher->id, $watcher->value, $watcher->data);
|
|
|
|
};
|
|
|
|
|
|
|
|
$this->timerCallback = function ($resource, $what, Watcher $watcher) {
|
|
|
|
if ($watcher->type & Watcher::DELAY) {
|
|
|
|
$this->cancel($watcher->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
$callback = $watcher->callback;
|
|
|
|
$callback($watcher->id, $watcher->data);
|
|
|
|
};
|
|
|
|
|
|
|
|
$this->signalCallback = function ($signum, $what, Watcher $watcher) {
|
|
|
|
$callback = $watcher->callback;
|
|
|
|
$callback($watcher->id, $watcher->value, $watcher->data);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public function __destruct() {
|
|
|
|
foreach ($this->events as $event) {
|
|
|
|
$event->free();
|
|
|
|
}
|
|
|
|
}
|
2017-01-05 17:32:03 -06:00
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function run() {
|
|
|
|
$active = self::$activeSignals;
|
|
|
|
|
|
|
|
foreach ($active as $event) {
|
|
|
|
$event->del();
|
|
|
|
}
|
|
|
|
|
|
|
|
self::$activeSignals = &$this->signals;
|
|
|
|
|
|
|
|
foreach ($this->signals as $event) {
|
|
|
|
$event->add();
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
parent::run();
|
|
|
|
} finally {
|
|
|
|
foreach ($this->signals as $event) {
|
|
|
|
$event->del();
|
|
|
|
}
|
|
|
|
|
|
|
|
self::$activeSignals = &$active;
|
|
|
|
|
|
|
|
foreach ($active as $event) {
|
|
|
|
$event->add();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-05 12:57:35 -06:00
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function stop() {
|
|
|
|
$this->handle->stop();
|
|
|
|
parent::stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
protected function dispatch($blocking) {
|
|
|
|
$this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
protected function activate(array $watchers) {
|
|
|
|
foreach ($watchers as $watcher) {
|
|
|
|
if (!isset($this->events[$id = $watcher->id])) {
|
|
|
|
switch ($watcher->type) {
|
|
|
|
case Watcher::READABLE:
|
|
|
|
$this->events[$id] = new \Event(
|
|
|
|
$this->handle,
|
|
|
|
$watcher->value,
|
|
|
|
\Event::READ | \Event::PERSIST,
|
|
|
|
$this->ioCallback,
|
|
|
|
$watcher
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Watcher::WRITABLE:
|
|
|
|
$this->events[$id] = new \Event(
|
|
|
|
$this->handle,
|
|
|
|
$watcher->value,
|
|
|
|
\Event::WRITE | \Event::PERSIST,
|
|
|
|
$this->ioCallback,
|
|
|
|
$watcher
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Watcher::DELAY:
|
|
|
|
case Watcher::REPEAT:
|
|
|
|
$flags = \Event::TIMEOUT;
|
|
|
|
if ($watcher->type === Watcher::REPEAT) {
|
|
|
|
$flags |= \Event::PERSIST;
|
|
|
|
}
|
|
|
|
$this->events[$id] = new \Event(
|
|
|
|
$this->handle,
|
|
|
|
-1,
|
|
|
|
$flags,
|
|
|
|
$this->timerCallback,
|
|
|
|
$watcher
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Watcher::SIGNAL:
|
|
|
|
$this->events[$id] = new \Event(
|
|
|
|
$this->handle,
|
|
|
|
$watcher->value,
|
|
|
|
\Event::SIGNAL | \Event::PERSIST,
|
|
|
|
$this->signalCallback,
|
|
|
|
$watcher
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new \DomainException("Unknown watcher type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ($watcher->type) {
|
|
|
|
case Watcher::DELAY:
|
|
|
|
case Watcher::REPEAT:
|
|
|
|
$this->events[$id]->add($watcher->value / self::MILLISEC_PER_SEC);
|
|
|
|
break;
|
2017-01-05 17:32:03 -06:00
|
|
|
|
|
|
|
case Watcher::SIGNAL:
|
|
|
|
$this->signals[$id] = $this->events[$id];
|
|
|
|
// No break
|
2017-01-05 12:57:35 -06:00
|
|
|
|
|
|
|
default:
|
|
|
|
$this->events[$id]->add();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
protected function deactivate(Watcher $watcher) {
|
|
|
|
if (isset($this->events[$id = $watcher->id])) {
|
|
|
|
$this->events[$id]->del();
|
2017-01-05 17:32:03 -06:00
|
|
|
|
|
|
|
if ($watcher->type === Watcher::SIGNAL) {
|
|
|
|
unset($this->signals[$id]);
|
|
|
|
}
|
2017-01-05 12:57:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function cancel($watcherIdentifier) {
|
|
|
|
parent::cancel($watcherIdentifier);
|
|
|
|
|
|
|
|
if (isset($this->events[$watcherIdentifier])) {
|
|
|
|
$this->events[$watcherIdentifier]->free();
|
|
|
|
unset($this->events[$watcherIdentifier]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function getHandle() {
|
|
|
|
return $this->handle;
|
|
|
|
}
|
|
|
|
}
|