-
Notifications
You must be signed in to change notification settings - Fork 3.8k
win, signal: flag to disable signal control handler #1168
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
Conversation
|
AFAIS we'd never reset the signal control handler. Is that what we want? If so, I'd like to suggest a different approach :-) Completely get rid of |
|
I simplified it further: I've moved |
|
|
||
| default: | ||
| /* Invalid signal. */ | ||
| return ERROR_INVALID_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.
This function served also to validate input. Now this would not complain on invalid input.
|
Can we have a test for this? |
|
One question: is it fine having a signal handler even though no signal watchers have registered? |
|
Added testing if @santigimeno Yes. We return |
src/win/signal.c
Outdated
| } | ||
| /* Test for other invalid signum values. */ | ||
| if (signum != SIGWINCH && (signum < 0 || signum >= NSIG)) { | ||
| return ERROR_INVALID_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.
You need to return a libuv error here. UV_EINVAL. Actually, you can probably combine this if with the one above.
| static void signal_cb(uv_signal_t* handle, int signum) { } | ||
|
|
||
| TEST_IMPL(win32_signum_number) { | ||
| uv_signal_t 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.
Use some other name for the handle please.
| #ifdef _WIN32 | ||
| static void signal_cb(uv_signal_t* handle, int signum) { } | ||
|
|
||
| TEST_IMPL(win32_signum_number) { |
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 test is OK, but we need one which tests the whole reason behind this patch. Can that be done?
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 don't think so, at least nothing easy comes to my mind.
|
@bzoz Sorry, I'm not sure I follow and probably I'm wrong but if I understand the code correctly, the signal handler is now always set on initialization whereas before this change was only set on the first watcher registration. Isn't this a change of behavior? |
|
@santigimeno I see what you mean. "Since there are no registered handles and the signal is ignored, will it affect applications in any way?" Is that it? I'd also like to know :-) |
|
@saghul I think so. With this change it looks like the signals are always handled in |
|
libuv supports Now, with this change the same thing will happen if no user registered handler is present . |
src/win/signal.c
Outdated
| InitializeCriticalSection(&uv__signal_lock); | ||
| if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) { | ||
| abort(); | ||
| } |
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.
drop braces for single statement conditionals
test/test-signal.c
Outdated
| ASSERT(uv_signal_start(&signal, signal_cb, SIGSEGV) == 0); | ||
| ASSERT(uv_signal_start(&signal, signal_cb, SIGTERM) == 0); | ||
| ASSERT(uv_signal_start(&signal, signal_cb, SIGABRT) == 0); | ||
| ASSERT(uv_signal_start(&signal, signal_cb, -1) == ERROR_INVALID_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.
these need to return UV_EINVAL
test/test-signal.c
Outdated
| ASSERT(uv_signal_start(&signal, signal_cb, 1024) == ERROR_INVALID_PARAMETER); | ||
| return 0; | ||
| } | ||
| #else _WIN32 |
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 #else
@bzoz sorry to bring this up again. After your last comment I'm not sure that, when no watchers are registered for any signal, the behavior will be the same with these changes as without them. |
|
@santigimeno It depends on what you mean by "behavior". There's a difference, in that SetConsoleCtrlHandler will be called uncoditionally now, where before it was called only when a signal handler was registered. However, there's no difference in behavior. The registered handler returns false as long as no libuv signal handlers are registered, which tells Windows that we didn't handle this signal, and the normal signal handling process should continue (which by default just terminates the process). I.e. the behavior is exactly the same as if no handler was installed at all. Also note that, as @bzoz mentioned above, this is what was already happening in the past if a libuv handler for say SIGINT was installed and signals other than CTRL_C_EVENT were received. Our handler would be called, but since no libuv handler was registered, we returned false and the normal Windows signal handling process continued. So there is no effective change in behavor. |
|
One thing I would like to note is that with this change, |
|
@mika-fischer thanks a lot for the thorough explanation! I think I get it now (my Windows knowledge is almost zero). |
|
Updated, PTAL @mika-fischer |
test/test-signal.c
Outdated
|
|
||
| /* For Windows we test only signum handling */ | ||
| #ifdef _WIN32 | ||
| static void signum_test_cb(uv_signal_t* handle, int signum) { } |
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.
add a "fatal" assert here, as we do in some other tests
|
Updated, PTAL |
| ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); | ||
| ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); | ||
| ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); | ||
| return 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.
add a MAKE_VALGRIND_HAPPY before returning 0, that will cleanup the loop.
saghul
left a comment
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.
One last nit, oterwise LGTM.
Adds flags that marks uv__signal_control_handler as disabled instead of removing it when uv__signal_control_handler_refs falls to zero. Trying to remove the controller from the controller handle itself leads to deadlock. Ref: nodejs/node#10165
|
Updated and squashed, PTAL |
|
Ping? |
|
Sorry for the delay @bzoz I'll merge it later today. |
Trying to remove the controller from the controller handle itself leads to deadlock. Fix it by always having the global signal handler engaged. Ref: nodejs/node#10165 PR-URL: #1168 Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
|
Post-closing comment: the original, (now-removed) logic to install and remove the console control handler existed because of the philosophy that libuv should limit the amount of global application state it affects unconditionally. For example, the application might opt not use use From that perspective I consider this patch a minor step back. Of course the fact that this patch fixes an actual problem that's affecting real applications trumps this academic concern of mine, and I also really like the significant reduction of complexity that this patch brings about. If the unconditional installation of the control handler does create problems for other users, I would suggest making it 'lazy' again but without reinstating the logic to remove the control handler. |
Trying to unregister signal handler from the handler itself can lead to deadlock. If it is the last handle, and
uv__signal_control_handler_refsfail to zero a call toSetConsoleCtrlHandleris made, which blocks until all control handlers exits.This PR adds flags that marks
uv__signal_control_handleras disabled instead of removing it whenuv__signal_control_handler_refsfalls to zero.Fixes part of: nodejs/node#10165