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

fix Ctrl-C / SIGINT behaviour for pyinstaller-made binaries, fixes #8155 (master) #8177

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 18 additions & 4 deletions src/borg/helpers/process.py
Expand Up @@ -195,6 +195,8 @@ def __init__(self):
self._action_triggered = False
self._action_done = False
self.ctx = signal_handler("SIGINT", self.handler)
self.debounce_interval = 20000000 # ns
self.last = None # monotonic time when we last processed SIGINT

def __bool__(self):
# this will be True (and stay True) after the first Ctrl-C/SIGINT
Expand All @@ -215,10 +217,22 @@ def action_completed(self):
self._action_done = True

def handler(self, sig_no, stack):
# handle the first ctrl-c / SIGINT.
self.__exit__(None, None, None)
self._sig_int_triggered = True
self._action_triggered = True
# Ignore a SIGINT if it comes too quickly after the last one, e.g. because it
# was caused by the same Ctrl-C key press and a parent process forwarded it to us.
# This can easily happen for the pyinstaller-made binaries because the bootloader
# process and the borg process are in same process group (see #8155), but maybe also
# under other circumstances.
now = time.monotonic_ns()
if self.last is None: # first SIGINT
self.last = now
self._sig_int_triggered = True
self._action_triggered = True
elif now - self.last >= self.debounce_interval: # second SIGINT
# restore the original signal handler for the 3rd+ SIGINT -
# this implies that this handler here loses control!
self.__exit__(None, None, None)
# handle 2nd SIGINT like the default handler would do it:
raise KeyboardInterrupt # python docs say this might show up at an arbitrary place.

def __enter__(self):
self.ctx.__enter__()
Expand Down