-
-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for signal handling #104
Conversation
src/Signal/Pcntl.php
Outdated
public function on($signal, callable $listener) | ||
{ | ||
if (!$this->enabled) { | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to fail silently or do we want to throw an exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should throw, otherwise an app cannot depend on signal handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaning towards the same, most other options add either more methods or silently fail and the consumer doesn't have clue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throwing an exception also makes sense to me 👍
src/Signal/Pcntl.php
Outdated
} | ||
|
||
if ($this->timer === null) { | ||
$this->timer = $this->loop->addPeriodicTimer(0.1, function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is checking for signals 10 times a second enough or should we do it 25 times a second or X per second?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling pcntl_signal_dispatch()
can simply be rolled into the main event loop after calling stream_select()
, since the latter is interrupted by the arrival of signals, regardless of the timeout parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to check, but that would only be for the stream_select()
loop right? As the other have signaling build in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I made that comment before I realized you were using the object with other loop implementations. Integrating it into StreamSelectLoop
should be the eventual goal then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, integration into the event loop is the ultimate goal here 👍
In the meantime, 0.1s is either too slow or too fast depending on what you're doing, so we may as well add an argument or constant at least.
tests/AbstractLoopTest.php
Outdated
public function testSignal() | ||
{ | ||
if (!extension_loaded('pcntl')) { | ||
$this->markTestSkipped('Signal test skipped because PCNTL extension isn\'t loaded.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another way around the support of PCNTL
would be an extra method that could be called to check if the loop supports signals. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could… though if an app depends on signals, likely it will throw anyway, so may as well throw from the onSignal()
method. Note that libevent, libev, and libuv support signal handling without the need of the pcntl
extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that libevent, libev, and libuv support signal handling without the need of the
pcntl
extension.
Yeah it's on the list for this PR 😎
src/LibEvLoop.php
Outdated
|
||
public function __construct() | ||
{ | ||
$this->loop = new EventLoop(); | ||
$this->futureTickQueue = new FutureTickQueue(); | ||
$this->timerEvents = new SplObjectStorage(); | ||
$this->signals = new Pcntl($this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LibEvLoop
should use the signal handling provided by the extension, as it is more reliable and integrates with the loop backend being used by the extension. Same goes for LibEventLoop
and ExtEventLoop
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's on the list at the top ^ 😎
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, so it is, missed that when focusing on the diff. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, your input is much appreciated 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I really like this feature and the direction this is heading! 👍 I think @trowski made some very good points about integration with other event loop implementations here 👍
README.md
Outdated
be notified about OS signals. This is useful to catch user interrupt signals or | ||
shutdown signals from tools like `supervisor` or `systemd`. | ||
|
||
The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover?
src/LoopInterface.php
Outdated
* | ||
* @return void | ||
*/ | ||
public function onSignal($signal, callable $listener); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be named addSignal()
for consistency with other methods?
Also, the docs should probably include whether multiple listeners can be attached to the same signal?
* | ||
* @return void | ||
*/ | ||
public function removeSignal($signal, callable $listener); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the same listener be added multiple times? If so, which one will be removed here?
Also, the docs should probably include what happens if the given signal or listener is not attached (NO-OP just like other methods?).
src/Signal/Pcntl.php
Outdated
public function on($signal, callable $listener) | ||
{ | ||
if (!$this->enabled) { | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throwing an exception also makes sense to me 👍
src/Signal/Pcntl.php
Outdated
} | ||
|
||
if ($this->timer === null) { | ||
$this->timer = $this->loop->addPeriodicTimer(0.1, function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, integration into the event loop is the ultimate goal here 👍
In the meantime, 0.1s is either too slow or too fast depending on what you're doing, so we may as well add an argument or constant at least.
tests/AbstractLoopTest.php
Outdated
}); | ||
|
||
$this->loop->futureTick(function () { | ||
posix_kill(posix_getpid(), SIGUSR1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that these functions may be disabled http://php.net/manual/en/posix.installation.php
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is a unit test I'm not that worried. Might put an if and fail in the if the function isn't available
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just skip the test if it isn't available.
@clue @trowski Reworked the signal handling for The question is what to do with trying to add the same listener more then once. We can either throw, ignore it silently, or just allow it. I've written it now in such a way that the latter works (or better should work, added tests for it this afternoon) and also removes all occurrences of a listener when you remove it. |
Had to rework the signal handler because not all loops support using the same listener more then once. That has all been resolve now and they all behave the same 😎 . Personally I think this would be the most transparent way of dealing the reused listeners. |
src/ExtEventLoop.php
Outdated
$this->signalEvents[$signal]->add(); | ||
}); | ||
$this->signals->on('off', function ($signal) { | ||
$this->futureTick(function () use ($signal) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this have to be in a future tick? This looks unexpected from a consumer perspective and would at least need some documentation here? I haven't verified this, but it looks like this could potentially cause a race condition, can you verify this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, the issue is that certain loops throw errors when you try to remove a signal handler while handling the given signal. In order to mitigate the race condition each loop does a check to ensure there are no registered signal handlers for the given signal. Should add documentation for it.
composer.json
Outdated
@@ -4,15 +4,17 @@ | |||
"keywords": ["event-loop", "asynchronous"], | |||
"license": "MIT", | |||
"require": { | |||
"php": ">=5.4.0" | |||
"php": ">=5.4.0", | |||
"evenement/evenement": "^3.0||^2.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this dependency is used throughout the ecosystem, but is it really worth it or should we try to keep this component stand-alone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well given the signal handler only has an on
and an off
even called once we don't really need it. I'll refactor and remove it.
README.md
Outdated
|
||
**Note: A listener can be added more then once to the same signal and it will be called | ||
for each time it is added. But on [`removeSignal`](#removeSignal) it is removed for all | ||
the times it has been added. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior looks really odd to me. Does it make sense to either reject adding the same listener multiple times or only remove a single instance so adding/removing behaves consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it should either error out or have another mechanism for removing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing a single instance would be easy to do. But it might be more consistent to only allow one occurrence of a instance per signal in the first place.
composer.json
Outdated
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "~4.8" | ||
}, | ||
"suggest": { | ||
"ext-libevent": ">=0.1.0", | ||
"ext-event": "~1.0", | ||
"ext-libev": "*" | ||
"ext-libev": "*", | ||
"ext-pcntl": "For signals support" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaict this is only need for the default loop, right? Documentation should probably be updated to explicitly say when this extension is recommended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, I assume you mean the documentation here and in README.md
. I'll update both
src/LoopInterface.php
Outdated
* | ||
* @throws UnsupportedFeatureException when signals | ||
* aren't supported by the loop, e.g. when required | ||
* extensions are missing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this method really throw? Looks like adding isn't possible in this case either, so this actually boils down to removing a non-existent listener?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is more about consistency between two methods than it is likely someone will call this method when addSignal
throws.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think that this situation shouldn't throw. Removing a non-existent listener does not throw, so why would removing a listener throw when it's impossible to add listeners in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me, they can catch the exception when trying top add it. I'll remove the exception on removing signal listeners 👍
@@ -196,6 +237,9 @@ private function waitForStreamActivity($timeout) | |||
$write = $this->writeStreams; | |||
|
|||
$available = $this->streamSelect($read, $write, $timeout); | |||
if ($this->pcntl) { | |||
\pcntl_signal_dispatch(); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be checked after every loop iteration and does this cause any performance issues? It's my understanding that a signal would interrupt the select()
call checked below, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A signal interrupts stream_select()
, correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signals aren't picked up when I change if ($this->pcntl) {
into if (false === $available && $this->pcntl) {
only dispatching when the loop received a signal. Not aware of any performance degradations.
src/SignalsHandler.php
Outdated
if (isset($this->signals[$signal]) && \count($this->signals[$signal]) === 0) { | ||
unset($this->signals[$signal]); | ||
$this->emit('off', [$signal]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That if
can be moved below the while
loop, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, kinda depends on the result of the discussion here: #104 (comment)
src/StreamSelectLoop.php
Outdated
$this->signals->on('on', function ($signal) { | ||
\pcntl_signal($signal, function ($signal) { | ||
$this->signals->call($signal); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That traps the signal and installs a process-wide handler. I guess it should at least be cleaned up in something like __destruct()
. Behavior with multiple loops needs to be defined somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Repeating that comment so it doesn't get hidden by changes. |
@WyriHaximus why are duplicates silently ignored instead of erroring out? |
@kelunik because it is consistent with how stream callables are handled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved from a user presepective and delegating technical approval to @clue.
Ping @clue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the direction this is heading! Only added some minor remarks:
examples/04-signals.php
Outdated
|
||
$loop = React\EventLoop\Factory::create(); | ||
|
||
$loop->onSignal(SIGINT, $func = function ($signal) use ($loop, &$func) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated?
src/ExtEventLoop.php
Outdated
$this->signalEvents[$signal]->add(); | ||
}, | ||
function ($signal) { | ||
$this->futureTick(function () use ($signal) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, why does this use futureTick()
and what consequence does this have? (see also below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In come loops removing the signal handled within the function handling a signal will make it fail hard. Another way would be to use future tick in the SignalHandler
when receiving the signal but that means the SignalHandler
becomes aware of the event loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I follow, can you provide a gist that shows this problem? Reading the documentation of our event loop implementations I could not find anything that supports this claim.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm odd can't reproduce is niet 🤐 . I'll remove the ticks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I'll add them again because this is what happens: https://travis-ci.org/reactphp/event-loop/jobs/290513376#L1401
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting find! Looks like this was actually bug in PHP (https://bugs.php.net/bug.php?id=62452) that was fixed with PHP 7. Removing this in the next tick has some consequences, so I wonder if this can be worked around by keeping a reference to the closure instead (see also the PHP bug for some workarounds).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clue yeah also know why I couldn't see it locally, didn't ran the tests on 5.6 locally 🤐 . Just committed a possible fix, since I can't test locally I'm going to run them on Travis and squash the commits once fixed if it needs more then one try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clue resolved the issue 🎉
src/LoopInterface.php
Outdated
* | ||
* @throws UnsupportedFeatureException when signals | ||
* aren't supported by the loop, e.g. when required | ||
* extensions are missing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think that this situation shouldn't throw. Removing a non-existent listener does not throw, so why would removing a listener throw when it's impossible to add listeners in the first place?
src/UnsupportedFeatureException.php
Outdated
{ | ||
return new self('Event loop feature "' . $feature . '" isn\'t supported by the "' . $loopName . '" event loop'); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds the first custom exception to this package, so I would much rather discuss this in a separate PR and remove here for now? 👍 A BadMethodCallException
seems to be a good replacement for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why Bad method call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kelunik What was your suggestion again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exception thrown if a callback refers to an undefined method or if some arguments are missing.
BadMethodCallException
is usually used in combination with __call
, not if requirements for a call are missing.
My suggestion is to keep a custom exception that makes things clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clue personally I moving more and more towards custom exceptions for each use case so the error handled in a specific manner for that error. Maybe we should have a discussion about if we want that in ReactPHP before adding a custom exception to a packages. I'll change it unless you and @jsor prefer this idea of a custom exception per error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not suggesting that "custom exception per error" is not a good idea (see above), merely that I think it makes sense to discuss this in a separate ticket because I would love to get this feature in already :-) Also note that this is the first method can may throw in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright I've swap it out with a core exception and we can have this discussion in another issue so we can get this feature in
|
||
final class SignalsHandlerTest extends TestCase | ||
{ | ||
public function testEmittedEventsAndCallHandling() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signal constants are only defined when PCNTL is loaded: http://php.net/manual/en/pcntl.constants.php
This test should probably check for this first. Also, maybe add a remark about this to the README?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defining in tests/bootstrap.php
when they don't exist in case PCNTL
isn't loaded
|
||
if (!defined('SIGUSR2')) { | ||
define('SIGUSR2', 2); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about making a package both Amp and ReactPHP can use that polyfills the signal constants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For two constants not really. Seems way to much overhead tbh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not only those two. It's also for using them with other reactor implementations if pcntl
isn't available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kelunik I agree with @WyriHaximus, this is probably overkill for this test suite. But I agree that it may make sense for consumers that want to rely on signal constant names, so I'd suggest go for it and create that package
examples/04-signals.php
Outdated
@@ -10,6 +10,7 @@ | |||
$loop->stop(); | |||
}); | |||
|
|||
// This timer is here to keep the loop alive, signaling an-sich doesn't do that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an-sich
-> by ifself
@WyriHaximus Could you add a test that a signal watcher doesn't keep the loop running if no other watcher exists? |
@kelunik just added the test and waiting for the results from travis |
src/UnsupportedFeatureException.php
Outdated
{ | ||
public static function create($feature, $loopName) | ||
{ | ||
return new self('Event loop feature "' . $feature . '" isn\'t supported by the "' . $loopName . '" event loop'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd go for a regular constructor here. The message should probably cover why the feature isn't supported (missing ext-pcntl
). The $loopName
should also be the class name instead of "stream_select"
IMO, but I'd argue that it's not needed in the message, because the used implementation will show up in the stack trace.
db0bda0
to
3f5457f
Compare
Ping @clue |
README.md
Outdated
@@ -292,6 +292,37 @@ echo 'a'; | |||
|
|||
See also [example #3](examples). | |||
|
|||
### addSignal() | |||
|
|||
**Note: Signaling is only available on Unix-like platform, Windows isn't supported.** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it makes sense to not support Windows in the first step. 👍
However, note that others (https://docs.python.org/3/library/signal.html#signal.signal or nodejs/node-v0.x-archive#1553) do provide limited, simulated signal handling supports on Windows. As such, I would suggest moving this note down a bit and make it more clear that this is not an interface limitations.
We should probably document the exception that we throw when signal handling is not supported. This should also cover Windows compatibility.
See also [example #4](examples). | ||
|
||
**Note: A listener can only be added once to the same signal, any attempts to add it | ||
more then once will be ignored.** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No objection to this limitation, but I would suggest making sure this is closer to the verbiage for our stream API (https://github.com/reactphp/event-loop/pull/110/files#diff-04c6e90faac2675aa89e2176d2eec7d8R312). What do you think about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated it, it isn't my strongest skill and I rather not let it block this PR thus I suggest if it needs work I do it in a follow up PR.
tests/AbstractLoopTest.php
Outdated
$this->loop->addTimer(0.1, function () {}); | ||
|
||
$this->assertRunFasterThan(0.2); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
examples/04-signals.php
Outdated
$loop->stop(); | ||
}); | ||
|
||
// This timer is here to keep the loop alive, signaling by itself doesn't do that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears unexpected to me and is apparently undocumented. I'm curious for the reasoning and documentation here, as I would clearly have expected this to behave otherwise. What is the motivation for not making this "keep the loop alive"? (Keeping consistency with other event loop listeners in mind here)
Also note that this is related to #107.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The motivation to not keeping the loop alive with signals was that there where not inputs into the loop kicking off more activity besides the signals. But now that I think about it signals COULD be used to kick off more activity. I'll update this PR shortly using a timer to keep the loop alive as long as signals are registered to it.
@clue reworked the PR so signals now keep the loop running |
41606c1
to
65c0a9b
Compare
examples/04-signals.php
Outdated
$loop->addSignal(SIGINT, $func = function ($signal) use ($loop, &$func) { | ||
echo 'Signal: ', (string)$signal, PHP_EOL; | ||
$loop->removeSignal(SIGINT, $func); | ||
$loop->stop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The $loop->stop()
doesn't do any harm, but it's not really needed anymore, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope no need for it there \o/
src/SignalsHandler.php
Outdated
{ | ||
if (count($this->signals) == 0 && $this->timer === null) { | ||
$this->timer = $this->loop->addPeriodicTimer(1, function () {}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest using a much higher interval do prevent the CPU from waking up every second. Also, maybe add a simple comment what this does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't really see the harm in once a second but increased it to five minutes
@clue updated as per your comments 👍 |
@clue solved merge conflict, could you review again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome job @WyriHaximus! 🎉 This should be squashed to a reasonable number of commits, otherwise LGTM! 🎉
$ git fetch origin
$ git checkout stoplichten
$ git rebase -i origin/master
# squash/fixup as applicable
01da14f
to
f8ad016
Compare
This PR adds OS signal handling. There are a few things of discussion, I'll post comments on the representing code lines.
Signal handlers: