summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTW <tw@waldmann-edv.de>2024-03-29 14:08:44 +0100
committerGitHub <noreply@github.com>2024-03-29 14:08:44 +0100
commit59e3a02a4035772202f725f0b625a49ec25411a8 (patch)
treed0b9f1f213afff06648dc7340f973a4453148353
parentf001aaa3e1e612950d6847173c9bfada9cea9343 (diff)
parentcaba23faec99c94a0039fc52a08f37031c7ad1cc (diff)
Merge pull request #8162 from ThomasWaldmann/debounce-sigint-1.2
fix Ctrl-C / SIGINT behaviour for pyinstaller-made binaries, fixes #8155 (1.2-maint)
-rw-r--r--src/borg/helpers/process.py22
1 files changed, 18 insertions, 4 deletions
diff --git a/src/borg/helpers/process.py b/src/borg/helpers/process.py
index 3dd19c7a4..785f191cb 100644
--- a/src/borg/helpers/process.py
+++ b/src/borg/helpers/process.py
@@ -188,6 +188,8 @@ class SigIntManager:
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
@@ -208,10 +210,22 @@ class SigIntManager:
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__()