Skip to content

Commit

Permalink
Add ability to unreference all types of events
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Sep 14, 2015
1 parent e883841 commit a25c073
Show file tree
Hide file tree
Showing 25 changed files with 545 additions and 82 deletions.
13 changes: 5 additions & 8 deletions src/Loop/AbstractLoop.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ abstract class AbstractLoop implements LoopInterface
private $immediateManager;

/**
* @var \Icicle\Loop\Manager\SignalManagerInterface
* @var \Icicle\Loop\Manager\SignalManagerInterface|null
*/
private $signalManager;

Expand Down Expand Up @@ -105,12 +105,8 @@ abstract protected function createSignalManager(EventFactoryInterface $eventFact
*/
public function __construct($enableSignals = true, EventFactoryInterface $eventFactory = null)
{
$this->eventFactory = $eventFactory;

if (null === $this->eventFactory) {
$this->eventFactory = $this->createEventFactory();
}

$this->eventFactory = $eventFactory ?: $this->createEventFactory();

$this->callableQueue = new CallableQueue(self::DEFAULT_MAX_DEPTH);

$this->immediateManager = $this->createImmediateManager($this->eventFactory);
Expand Down Expand Up @@ -195,7 +191,8 @@ public function isEmpty()
&& $this->awaitManager->isEmpty()
&& $this->timerManager->isEmpty()
&& $this->callableQueue->isEmpty()
&& $this->immediateManager->isEmpty();
&& $this->immediateManager->isEmpty()
&& (null === $this->signalManager || $this->signalManager->isEmpty());
}

/**
Expand Down
23 changes: 23 additions & 0 deletions src/Loop/Events/EventInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of Icicle, a library for writing asynchronous code in PHP using promises and coroutines.
*
* @copyright 2014-2015 Aaron Piotrowski. All rights reserved.
* @license Apache-2.0 See the LICENSE file that was distributed with this source code for more information.
*/

namespace Icicle\Loop\Events;

interface EventInterface
{
/**
* An unreferenced event will allow the event loop to exit if no other events are pending.
*/
public function unreference();

/**
* Adds a reference to the event, causing the event loop to continue to run as long as the event is still pending.
*/
public function reference();
}
27 changes: 27 additions & 0 deletions src/Loop/Events/Immediate.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class Immediate implements ImmediateInterface
*/
private $args;

/**
* @var bool
*/
private $referenced = true;

/**
* @param \Icicle\Loop\Manager\ImmediateManagerInterface $manager
* @param callable $callback Function called when the interval expires.
Expand Down Expand Up @@ -75,6 +80,10 @@ public function isPending()
public function execute()
{
$this->manager->execute($this);

if (!$this->referenced) {
$this->manager->unreference($this);
}
}

/**
Expand All @@ -84,4 +93,22 @@ public function cancel()
{
$this->manager->cancel($this);
}

/**
* {@inheritdoc}
*/
public function unreference()
{
$this->referenced = false;
$this->manager->unreference($this);
}

/**
* {@inheritdoc}
*/
public function reference()
{
$this->referenced = true;
$this->manager->reference($this);
}
}
4 changes: 2 additions & 2 deletions src/Loop/Events/ImmediateInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Icicle\Loop\Events;

interface ImmediateInterface
interface ImmediateInterface extends EventInterface
{
/**
* @return bool
Expand All @@ -30,7 +30,7 @@ public function cancel();
* Calls the callback associated with the immediate.
*/
public function call();

/**
* Alias of call().
*/
Expand Down
27 changes: 27 additions & 0 deletions src/Loop/Events/Signal.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class Signal implements SignalInterface
*/
private $signo;

/**
* @var bool
*/
private $referenced = false;

/**
* @param \Icicle\Loop\Manager\SignalManagerInterface $manager
* @param int $signo
Expand Down Expand Up @@ -71,6 +76,10 @@ public function setCallback(callable $callback)
public function enable()
{
$this->manager->enable($this);

if ($this->referenced) {
$this->manager->reference($this);
}
}

/**
Expand All @@ -96,4 +105,22 @@ public function getSignal()
{
return $this->signo;
}

/**
* {@inheritdoc}
*/
public function unreference()
{
$this->referenced = false;
$this->manager->unreference($this);
}

/**
* {@inheritdoc}
*/
public function reference()
{
$this->referenced = true;
$this->manager->reference($this);
}
}
4 changes: 2 additions & 2 deletions src/Loop/Events/SignalInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@

namespace Icicle\Loop\Events;

interface SignalInterface
interface SignalInterface extends EventInterface
{
/**
* Calls the callback associated with the timer.
*/
public function call();

/**
* Alias of call().
*/
Expand Down
16 changes: 16 additions & 0 deletions src/Loop/Events/SocketEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,20 @@ public function getResource()
{
return $this->resource;
}

/**
* {@inheritdoc}
*/
public function unreference()
{
$this->manager->unreference($this);
}

/**
* {@inheritdoc}
*/
public function reference()
{
$this->manager->reference($this);
}
}
2 changes: 1 addition & 1 deletion src/Loop/Events/SocketEventInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Icicle\Loop\Events;

interface SocketEventInterface
interface SocketEventInterface extends EventInterface
{
/**
* Returns the PHP resource.
Expand Down
2 changes: 1 addition & 1 deletion src/Loop/Events/Timer.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function start()
$this->manager->start($this);

if (!$this->referenced) {
$this->unreference();
$this->manager->unreference($this);
}
}

Expand Down
14 changes: 2 additions & 12 deletions src/Loop/Events/TimerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Icicle\Loop\Events;

interface TimerInterface
interface TimerInterface extends EventInterface
{
/**
* @return bool
Expand Down Expand Up @@ -40,21 +40,11 @@ public function getInterval();
*/
public function isPeriodic();

/**
* An unreferenced timer will allow the event loop to exit if no other events are pending.
*/
public function unreference();

/**
* Adds a reference to the timer, causing the event loop to continue to run if the timer is still pending.
*/
public function reference();

/**
* Calls the callback associated with the timer.
*/
public function call();

/**
* Alias of call().
*/
Expand Down
37 changes: 37 additions & 0 deletions src/Loop/Manager/AbstractSignalManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ abstract class AbstractSignalManager implements SignalManagerInterface
*/
private $signals = [];

/**
* @var \SplObjectStorage
*/
private $referenced;

/**
* @param \Icicle\Loop\LoopInterface $loop
* @param \Icicle\Loop\Events\EventFactoryInterface $factory
Expand All @@ -43,6 +48,8 @@ public function __construct(LoopInterface $loop, EventFactoryInterface $factory)
foreach ($this->getSignalList() as $signo) {
$this->signals[$signo] = new \SplObjectStorage();
}

$this->referenced = new \SplObjectStorage();
}

/**
Expand Down Expand Up @@ -80,6 +87,8 @@ public function disable(SignalInterface $signal)
if (isset($this->signals[$signo]) && $this->signals[$signo]->contains($signal)) {
$this->signals[$signo]->detach($signal);
}

$this->referenced->detach($signal);
}

/**
Expand All @@ -102,6 +111,34 @@ public function clear()
}
}

/**
* {@inheritdoc}
*/
public function reference(SignalInterface $signal)
{
$signo = $signal->getSignal();

if ($this->signals[$signo]->contains($signal)) {
$this->referenced->attach($signal);
}
}

/**
* {@inheritdoc}
*/
public function unreference(SignalInterface $signal)
{
$this->referenced->detach($signal);
}

/**
* {@inheritdoc}
*/
public function isEmpty()
{
return !$this->referenced->count();
}

/**
* Returns an array of signals to be handled. Exploits the fact that PHP will not notice the signal constants are
* undefined if the pcntl extension is not installed.
Expand Down
34 changes: 30 additions & 4 deletions src/Loop/Manager/Ev/SocketManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class SocketManager implements SocketManagerInterface
*/
private $timers = [];

/**
* @var \Icicle\Loop\Events\SocketEventInterface[]
*/
private $unreferenced = [];

/**
* @var callable
*/
Expand Down Expand Up @@ -102,8 +107,8 @@ public function __destruct()
*/
public function isEmpty()
{
foreach ($this->events as $event) {
if ($event->is_active) {
foreach ($this->events as $id => $event) {
if ($event->is_active && !isset($this->unreferenced[$id])) {
return false;
}
}
Expand Down Expand Up @@ -197,7 +202,7 @@ public function free(SocketEventInterface $socket)

if (isset($this->events[$id]) && $socket === $this->events[$id]->data) {
$this->events[$id]->stop();
unset($this->events[$id]);
unset($this->events[$id], $this->unreferenced[$id]);

if (isset($this->timers[$id])) {
$this->timers[$id]->stop();
Expand All @@ -215,7 +220,27 @@ public function isFreed(SocketEventInterface $socket)

return !isset($this->events[$id]) || $socket !== $this->events[$id]->data;
}


/**
* {@inheritdoc}
*/
public function reference(SocketEventInterface $socket)
{
unset($this->unreferenced[(int) $socket->getResource()]);
}

/**
* {@inheritdoc}
*/
public function unreference(SocketEventInterface $socket)
{
$id = (int) $socket->getResource();

if (isset($this->events[$id]) && $socket === $this->events[$id]->data) {
$this->unreferenced = $socket;
}
}

/**
* {@inheritdoc}
*/
Expand All @@ -230,6 +255,7 @@ public function clear()
}

$this->events = [];
$this->unreferenced = [];
$this->timers = [];
}
}

0 comments on commit a25c073

Please sign in to comment.