Index: xz/src/xz/signals.c |
=================================================================== |
--- xz/src/xz/signals.c (revision 0) |
+++ xz/src/xz/signals.c (revision 0) |
@@ -0,0 +1,189 @@ |
+/////////////////////////////////////////////////////////////////////////////// |
+// |
+/// \file signals.c |
+/// \brief Handling signals to abort operation |
+// |
+// Author: Lasse Collin |
+// |
+// This file has been put into the public domain. |
+// You can do whatever you want with this file. |
+// |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "private.h" |
+ |
+ |
+volatile sig_atomic_t user_abort = false; |
+ |
+ |
+#if !(defined(_WIN32) && !defined(__CYGWIN__)) |
+ |
+/// If we were interrupted by a signal, we store the signal number so that |
+/// we can raise that signal to kill the program when all cleanups have |
+/// been done. |
+static volatile sig_atomic_t exit_signal = 0; |
+ |
+/// Mask of signals for which have have established a signal handler to set |
+/// user_abort to true. |
+static sigset_t hooked_signals; |
+ |
+/// True once signals_init() has finished. This is used to skip blocking |
+/// signals (with uninitialized hooked_signals) if signals_block() and |
+/// signals_unblock() are called before signals_init() has been called. |
+static bool signals_are_initialized = false; |
+ |
+/// signals_block() and signals_unblock() can be called recursively. |
+static size_t signals_block_count = 0; |
+ |
+ |
+static void |
+signal_handler(int sig) |
+{ |
+ exit_signal = sig; |
+ user_abort = true; |
+ return; |
+} |
+ |
+ |
+extern void |
+signals_init(void) |
+{ |
+ // List of signals for which we establish the signal handler. |
+ static const int sigs[] = { |
+ SIGINT, |
+ SIGTERM, |
+#ifdef SIGHUP |
+ SIGHUP, |
+#endif |
+#ifdef SIGPIPE |
+ SIGPIPE, |
+#endif |
+#ifdef SIGXCPU |
+ SIGXCPU, |
+#endif |
+#ifdef SIGXFSZ |
+ SIGXFSZ, |
+#endif |
+ }; |
+ |
+ // Mask of the signals for which we have established a signal handler. |
+ sigemptyset(&hooked_signals); |
+ for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) |
+ sigaddset(&hooked_signals, sigs[i]); |
+ |
+ struct sigaction sa; |
+ |
+ // All the signals that we handle we also blocked while the signal |
+ // handler runs. |
+ sa.sa_mask = hooked_signals; |
+ |
+ // Don't set SA_RESTART, because we want EINTR so that we can check |
+ // for user_abort and cleanup before exiting. We block the signals |
+ // for which we have established a handler when we don't want EINTR. |
+ sa.sa_flags = 0; |
+ sa.sa_handler = &signal_handler; |
+ |
+ for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) { |
+ // If the parent process has left some signals ignored, |
+ // we don't unignore them. |
+ struct sigaction old; |
+ if (sigaction(sigs[i], NULL, &old) == 0 |
+ && old.sa_handler == SIG_IGN) |
+ continue; |
+ |
+ // Establish the signal handler. |
+ if (sigaction(sigs[i], &sa, NULL)) |
+ message_signal_handler(); |
+ } |
+ |
+ signals_are_initialized = true; |
+ |
+ return; |
+} |
+ |
+ |
+#ifndef __VMS |
+extern void |
+signals_block(void) |
+{ |
+ if (signals_are_initialized) { |
+ if (signals_block_count++ == 0) { |
+ const int saved_errno = errno; |
+ mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL); |
+ errno = saved_errno; |
+ } |
+ } |
+ |
+ return; |
+} |
+ |
+ |
+extern void |
+signals_unblock(void) |
+{ |
+ if (signals_are_initialized) { |
+ assert(signals_block_count > 0); |
+ |
+ if (--signals_block_count == 0) { |
+ const int saved_errno = errno; |
+ mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL); |
+ errno = saved_errno; |
+ } |
+ } |
+ |
+ return; |
+} |
+#endif |
+ |
+ |
+extern void |
+signals_exit(void) |
+{ |
+ const int sig = exit_signal; |
+ |
+ if (sig != 0) { |
+ struct sigaction sa; |
+ sa.sa_handler = SIG_DFL; |
+ sigfillset(&sa.sa_mask); |
+ sa.sa_flags = 0; |
+ sigaction(sig, &sa, NULL); |
+ raise(exit_signal); |
+ } |
+ |
+ return; |
+} |
+ |
+#else |
+ |
+// While Windows has some very basic signal handling functions as required |
+// by C89, they are not really used, and e.g. SIGINT doesn't work exactly |
+// the way it does on POSIX (Windows creates a new thread for the signal |
+// handler). Instead, we use SetConsoleCtrlHandler() to catch user |
+// pressing C-c, because that seems to be the recommended way to do it. |
+// |
+// NOTE: This doesn't work under MSYS. Trying with SIGINT doesn't work |
+// either even if it appeared to work at first. So test using Windows |
+// console window. |
+ |
+static BOOL WINAPI |
+signal_handler(DWORD type lzma_attribute((unused))) |
+{ |
+ // Since we don't get a signal number which we could raise() at |
+ // signals_exit() like on POSIX, just set the exit status to |
+ // indicate an error, so that we cannot return with zero exit status. |
+ set_exit_status(E_ERROR); |
+ user_abort = true; |
+ return TRUE; |
+} |
+ |
+ |
+extern void |
+signals_init(void) |
+{ |
+ if (!SetConsoleCtrlHandler(&signal_handler, TRUE)) |
+ message_signal_handler(); |
+ |
+ return; |
+} |
+ |
+#endif |
Property changes on: xz/src/xz/signals.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |