Skip to content
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

Signal handling fixes #10758

Merged
merged 8 commits into from Sep 14, 2020
Merged

Conversation

gshuflin
Copy link
Contributor

@gshuflin gshuflin commented Sep 11, 2020

Problem

Ideally, pants should exit promptly when a user hits Ctrl-C in the terminal, regardless of how it is configured to run or what it is running. cf. #10051 and other general observations made while using pants, there are still a few cases where pants does not respond quickly to a Ctrl-C and hangs or otherwise takes a while to quit. This commit is an attempt to fix these cases.

Solution

In the --debug case, the problem turned out to be that we were explicitly disabling SIGINT handling in the case where pants was running an InteractiveProcess. For the non-pantsd case, this is desirable - we use the InteractiveProcess abstraction for test --debug and a few other cases where we legitimately want a pants subprocess to take over the terminal and do its own signal handling. But when pantsd is running, we don't want to explicitly disable SIGINT handling, because that means that pantsd will ignore a signal from its own client process. This commit solves the problem by adding a flag to SignalHandler to indicate whether this is a pantsd run, and doesn't ignore SIGINT if it is.

Some other instances of pants ignoring prompt signal handling are caused by rust code not heeding the Python interrupt state triggered by SIGINT, resulting in pants not quitting until execution returns to the Python main thread. This commit works around this by having the Python signal handling infrastructure set a flag on ExceptionSink once it has handled a signal that would cause pants to terminate. A python helper function is passed into the main execution loop in scheduler.rs that checks for the presence of this flag, and breaks the loop to terminate the engine if it finds that the flag is set.

Result

Ctrl-C should now work in the test --debug case with pantsd, and work in the --no-pantsd case when any kind of test is running. It still does seem to take more than one hit of Ctrl-C to fully quit pants in some cases, though, which will be addressed in followup commits.

@gshuflin gshuflin marked this pull request as ready for review September 11, 2020 04:22
Copy link
Sponsor Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@@ -474,6 +476,19 @@ impl Scheduler {
session.maybe_display_initialize(&self.core.executor, &sender);
self.execute_helper(request, session, sender);
let result = loop {
match externs::call(&python_signal, &[]) {
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to move this out into a helper function to keep the loop body small. You might also move the check "after" the call to recv_timeout but before the match... as the most likely time to receive a signal is while we are waiting, and reacting to it before we render the UI/print_stderr/etc will be the most responsive.

return Err(ExecutionTermination::KeyboardInterrupt);
}
}
Err(e) => {
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function is running in the main thread (it won't always be), it's possible that the error type received here will actually be KeyboardInterrupt: in which case you'd want to return ExecutionTermination::KeyboardInterrupt.

@gshuflin gshuflin force-pushed the pantsd_signal_handling2 branch 2 times, most recently from 875acca to abcebc8 Compare September 14, 2020 17:00
@coveralls
Copy link

coveralls commented Sep 14, 2020

Coverage Status

Coverage remained the same at 0.0% when pulling 3e3f452 on gshuflin:pantsd_signal_handling2 into fa71675 on pantsbuild:master.

Copy link
Sponsor Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines 117 to 119
# An instance of `SignalHandler` which is invoked to handle a static set of specific
# nonfatal signals (these signal handlers are allowed to make pants exit, but unlike SIGSEGV they
# don't need to exit immediately).
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This information was potentially useful... did you determine that it is no longer accurate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope that was an extraneous delete, restoring

Comment on lines +312 to 313
ExceptionSink.toggle_ignoring_sigint(True)
return self._scheduler.run_local_interactive_process(request)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this would be a good place to use a context manager / with block... any idea why we stopped doing that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code never used a with block, although I agree that that would be a good improvement, and I might implement that shortly in a followup commit.


pub fn call(func: &Value, args: &[Value]) -> Result<Value, Failure> {
let output = call_function(func, args);
let gil = Python::acquire_gil();
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could avoid re-acquiring the GIL here unless this fails, by moving let gil inside the map_err.

As well as do some additional refactoring.

[ci skip-rust]

[ci skip-build-wheels]
[ci skip-build-wheels]
[ci skip-build-wheels]
[ci skip-build-wheels]
[ci skip-build-wheels]
[ci skip-build-wheels]
[ci skip-build-wheels]
@gshuflin gshuflin merged commit bfd65d8 into pantsbuild:master Sep 14, 2020
@gshuflin gshuflin deleted the pantsd_signal_handling2 branch September 14, 2020 23:54
@Eric-Arellano
Copy link
Contributor

Yay, ./pants --no-pantsd repl and ./pants --no-pantsd repl --shell=ipython behave identically to running without Pants!

▶ ./pants --no-pantsd repl
Python 3.6.10 (default, May 12 2020, 19:47:44)
[GCC 4.2.1 Compatible Apple LLVM 11.0.0 (clang-1100.0.33.8)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> [ctrl-c]
KeyboardInterrupt
>>> [ctrl-d]
now exiting InteractiveConsole...
▶ ./pants --no-pantsd repl --shell=ipython
23:05:07.69 [INFO] Completed: Building ipython.pex with 1 requirement: ipython==7.16.1
Python 3.6.10 (default, May 12 2020, 19:47:44)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.16.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: [ctrl-c ignored; ctrl-d]
Do you really want to exit ([y]/n)? y

Pantsd isn't quite right, but an improvement. If you use ctrl-c, it will immediately break out of the process. It would be better to do the KeyboardInterrupt like you do without Pantsd and without Pants, but this seems acceptable.

ctrl-d works on a clean run. But then there's a weird bug. Reproduce with:

  1. Run ./pants repl. Use ctrl-c. Should exit fine.
  2. Run ./pants repl again. It should immediately start up the process for you. Now do ctrl-d or ctrl-c. Either you use, the process will not exit cleanly:
▶ ./pants repl
>>> [ctrl-c]

code/projects/pants  master ✔                                             29m  ⍉
▶ O

code/projects/pants  master ✔                                             29m  ⍉
▶ O

I can't delete the O, and when I type something, the characters get corrupted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants