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
Bootloader: forward signals to bundled application #3515
Conversation
CI build is looking good so far. I'm optimistically declaring this ready for review. |
Added Other Appveyor errors seem unrelated to this PR. |
There's a subtle problem with this PR: messing with SIGCHLD makes the boot loader unable to I have a fix in flight; will hopefully push soon, along with a related piece of functionality that I think is required here (the ability to ignore signals in the boot loader if desired). |
In the meanwhile: thanks for working on this :-) I'm expecting our updates. |
I'm currently stuck on this issue: I have a test that breaks with I've just pushed the branch in its current broken state to show what I mean. Suggestions welcome. |
If the failure in Travis looks like my local testing, it'll show that the call to But, I've also been seeing strange results where debug prints that I insert in the parent don't show up in the output, even though the child process is still forked and runs the test. So there might be something wonky with my test environment. I'm very curious to see what the same test in Travis looks like. |
...and of course, since I wasn't thinking and pushed commits to another PR before this one, it's going to be a while before this test runs. 🤦♂️ |
Lol and as I write that, the build kicked off after all. Pleasantly surprised. |
Ok, so - the failures I see locally don’t show up in Travis. I need to fix the Figuring out the issue with my local test env can be a part of #3519. |
@htgoebel this should be good for review; I just pushed the |
Rebased, resolved conflicts, squashed a bit. |
@htgoebel any news on this? Anything else you need me to do? |
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.
Thanks a lot for this pull-request. Sorry for not answering earlier, I'm busy with my day-job.
This looks good for me and I like the test-suite you've created. Nevertheless I added some comments, most of which are nit-picking to keep the code maintainable for another 10 years.
PyInstaller/building/api.py
Outdated
@@ -56,7 +56,7 @@ def __init__(self, *tocs, **kwargs): | |||
ModuleGraph. | |||
|
|||
kwargs | |||
Possible keywork arguments: | |||
Possible keyword arguments: |
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 is unrelated to this change and should go into a commit of its own. Same for typo fixed below. I'd even abstain from fixing then, since it is still understandable.
tests/functional/test_signals.py
Outdated
|
||
target = child | ||
|
||
eprint('signalling {{}} ({{}})'.format(target.name(), target.pid)) |
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.
By using %s
interpolation, this becomes easer to read. Same for all other cases below. and above.
Also: Why not passing several args to eprint:
``
eprint('signaling', target.name(), '(%s)' % target.pid)
This is why print is designed as it is :-) And you can get rid of the formatting at all in many cases.
tests/functional/test_signals.py
Outdated
print('Bootloader did not fork; test is invalid') | ||
sys.exit(0) | ||
|
||
target = child |
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 trailing target = child
looks lost. What about this structure:
if parent.name ...
...
elif ignore:
...
else:
...
tests/functional/test_signals.py
Outdated
if signame in ['SIGCHLD', 'SIGCLD']: | ||
pytest.xfail( | ||
'Messing with {} interferes with bootloader'.format(signame) | ||
) |
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.
Please add a short comment. I assume these signals are not filtered out when building the signals
list to spot whether the bootloader actually does not forward these to the child?!
bootloader/src/pyi_utils.c
Outdated
VS("LOADER: Restoring signal handlers\n"); | ||
for (signum = 0; signum < num_signals; ++signum) { | ||
if (handlers[signum] != SIG_ERR) { | ||
signal(signum, handlers[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.
Not setting the signal back to SIG_DFL (as the old code did) is worth a commit of its own. Thus when reading the commit messages one can easily spot this relevant change.
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.
@htgoebel It's pretty insignificant, IMO, particularly since the bootloader (parent) is about to exit after this. I'd be more inclined to switch back to using SIG_DFL.
bootloader/src/pyi_utils.c
Outdated
|
||
#ifndef sighandler_t | ||
typedef void (*sighandler_t)(int); | ||
#endif |
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.
Please move this near the top of the file, where other type-defs are.
{ | ||
kill(child_pid, signal); | ||
VS("LOADER: Forwarding signal %d to child pid %d\n", signum, child_pid); | ||
kill(child_pid, 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.
Renaming parameters is a non-functional change, please revert this. This will increase the patch-sice and the time to review and understand what this change is doing.
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 previous name, signal
, was shadowing a function name. Like you, I'm interested in the long-term maintainability of the code I write, so I fixed this issue. I've already split this tiny function into two handlers; even calling this a rename is a stretch.
bootloader/src/pyi_utils.c
Outdated
@@ -850,21 +855,44 @@ set_systemd_env() | |||
pid_t child_pid = 0; | |||
|
|||
static void | |||
_signal_handler(int signal) | |||
_ignore_signal(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.
Rename to something telling this is a handler, too. E.g. ignoring_signal_handler
. Also a comment would be nice.
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.
What would the comment say that isn't already obvious from the function name and log message?
@@ -553,7 +553,7 @@ pyi_arch_status_free_memory(ARCHIVE_STATUS *archive_status) | |||
* for freeing it. | |||
*/ | |||
char * | |||
pyi_arch_get_option(ARCHIVE_STATUS * status, char * optname) | |||
pyi_arch_get_option(const ARCHIVE_STATUS * status, char * optname) |
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 changes (adding "const") are unrelated to this pull-request and should go into a commit of its own.
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 fact, these were required, because I added an argument of type const ARCHIVE_STATUS *
to pyi_utils_create_child
below.
I can either make these existing methods const-correct or I can make the new argument const-incorrect. I chose the option that I felt was a net improvement. Please let me know if you disagree.
"Useful in situations where e.g. a supervisor " | ||
"process signals both the bootloader and child " | ||
"(e.g. via a process group) to avoid signalling " | ||
"the child twice.")) |
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.
What do you think about moving this below --noupx
, or even into the "Rarely used special options:" section?
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.
Sure; though I'm not really sure how common this use case is, I lean towards the latter.
Addressed feedback and pushed new version. |
Forward more signals
All the signals, to be precise. (Well, all the signals that can be handled.)
If the caller of
pyinstaller
specifies the--bootloader-ignore-signals
CLI flag, all signals will be ignored instead. This is useful if e.g. a supervisor process signals the bootloader's process group; otherwise, the child process would be signaled twice.Note: docs forthcoming for the new flag (and perhaps this overall behavior), pending feedback on the overall approach.
New functional test
This test checks whether signals sent to an pyinstaller-built executable can be handled
using
signal.signal(...)
in the Python code.Summary of my manual testing so far (before this test):
--onedir
and--onefile
modes.--onefile
modeAt present, I'm assuming that an application using pyinstaller could reasonably want to handle any handleable signal (i.e. not SIGKILL or SIGSTOP). If there are any exceptions to this, or if this needs to be handled more selectively for reasons I'm not aware of, I'd be glad to hear about it.
Closes #3514.