1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Handling signals to abort operation
6 // Copyright (C) 2007-2009 Lasse Collin
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 ///////////////////////////////////////////////////////////////////////////////
23 volatile sig_atomic_t user_abort = false;
28 /// If we were interrupted by a signal, we store the signal number so that
29 /// we can raise that signal to kill the program when all cleanups have
31 static volatile sig_atomic_t exit_signal = 0;
33 /// Mask of signals for which have have established a signal handler to set
34 /// user_abort to true.
35 static sigset_t hooked_signals;
37 /// signals_block() and signals_unblock() can be called recursively.
38 static size_t signals_block_count = 0;
42 signal_handler(int sig)
53 // List of signals for which we establish the signal handler.
54 static const int sigs[] = {
71 // Mask of the signals for which we have established a signal handler.
72 sigemptyset(&hooked_signals);
73 for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
74 sigaddset(&hooked_signals, sigs[i]);
78 // All the signals that we handle we also blocked while the signal
80 sa.sa_mask = hooked_signals;
82 // Don't set SA_RESTART, because we want EINTR so that we can check
83 // for user_abort and cleanup before exiting. We block the signals
84 // for which we have established a handler when we don't want EINTR.
86 sa.sa_handler = &signal_handler;
88 for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
89 // If the parent process has left some signals ignored,
90 // we don't unignore them.
92 if (sigaction(sigs[i], NULL, &old) == 0
93 && old.sa_handler == SIG_IGN)
96 // Establish the signal handler.
97 if (sigaction(sigs[i], &sa, NULL))
98 message_signal_handler();
108 if (signals_block_count++ == 0) {
109 const int saved_errno = errno;
110 mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL);
119 signals_unblock(void)
121 assert(signals_block_count > 0);
123 if (--signals_block_count == 0) {
124 const int saved_errno = errno;
125 mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL);
136 const int sig = exit_signal;
140 sa.sa_handler = SIG_DFL;
141 sigfillset(&sa.sa_mask);
143 sigaction(sig, &sa, NULL);
152 // While Windows has some very basic signal handling functions as required
153 // by C89, they are not really used, or so I understood. Instead, we use
154 // SetConsoleCtrlHandler() to catch user pressing C-c.
160 signal_handler(DWORD type lzma_attribute((unused)))
162 // Since we don't get a signal number which we could raise() at
163 // signals_exit() like on POSIX, just set the exit status to
164 // indicate an error, so that we cannot return with zero exit status.
165 set_exit_status(E_ERROR);
174 if (!SetConsoleCtrlHandler(&signal_handler, TRUE))
175 message_signal_handler();