]> icculus.org git repositories - icculus/xz.git/blob - src/xz/signals.c
Various changes.
[icculus/xz.git] / src / xz / signals.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       signals.c
4 /// \brief      Handling signals to abort operation
5 //
6 //  Author:     Lasse Collin
7 //
8 //  This file has been put into the public domain.
9 //  You can do whatever you want with this file.
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12
13 #include "private.h"
14
15
16 volatile sig_atomic_t user_abort = false;
17
18
19 #ifndef _WIN32
20
21 /// If we were interrupted by a signal, we store the signal number so that
22 /// we can raise that signal to kill the program when all cleanups have
23 /// been done.
24 static volatile sig_atomic_t exit_signal = 0;
25
26 /// Mask of signals for which have have established a signal handler to set
27 /// user_abort to true.
28 static sigset_t hooked_signals;
29
30 /// signals_block() and signals_unblock() can be called recursively.
31 static size_t signals_block_count = 0;
32
33
34 static void
35 signal_handler(int sig)
36 {
37         exit_signal = sig;
38         user_abort = true;
39         return;
40 }
41
42
43 extern void
44 signals_init(void)
45 {
46         // List of signals for which we establish the signal handler.
47         static const int sigs[] = {
48                 SIGINT,
49                 SIGTERM,
50 #ifdef SIGHUP
51                 SIGHUP,
52 #endif
53 #ifdef SIGPIPE
54                 SIGPIPE,
55 #endif
56 #ifdef SIGXCPU
57                 SIGXCPU,
58 #endif
59 #ifdef SIGXFSZ
60                 SIGXFSZ,
61 #endif
62         };
63
64         // Mask of the signals for which we have established a signal handler.
65         sigemptyset(&hooked_signals);
66         for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
67                 sigaddset(&hooked_signals, sigs[i]);
68
69         struct sigaction sa;
70
71         // All the signals that we handle we also blocked while the signal
72         // handler runs.
73         sa.sa_mask = hooked_signals;
74
75         // Don't set SA_RESTART, because we want EINTR so that we can check
76         // for user_abort and cleanup before exiting. We block the signals
77         // for which we have established a handler when we don't want EINTR.
78         sa.sa_flags = 0;
79         sa.sa_handler = &signal_handler;
80
81         for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
82                 // If the parent process has left some signals ignored,
83                 // we don't unignore them.
84                 struct sigaction old;
85                 if (sigaction(sigs[i], NULL, &old) == 0
86                                 && old.sa_handler == SIG_IGN)
87                         continue;
88
89                 // Establish the signal handler.
90                 if (sigaction(sigs[i], &sa, NULL))
91                         message_signal_handler();
92         }
93
94         return;
95 }
96
97
98 #ifndef __VMS
99 extern void
100 signals_block(void)
101 {
102         if (signals_block_count++ == 0) {
103                 const int saved_errno = errno;
104                 mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL);
105                 errno = saved_errno;
106         }
107
108         return;
109 }
110
111
112 extern void
113 signals_unblock(void)
114 {
115         assert(signals_block_count > 0);
116
117         if (--signals_block_count == 0) {
118                 const int saved_errno = errno;
119                 mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL);
120                 errno = saved_errno;
121         }
122
123         return;
124 }
125 #endif
126
127
128 extern void
129 signals_exit(void)
130 {
131         const int sig = exit_signal;
132
133         if (sig != 0) {
134                 struct sigaction sa;
135                 sa.sa_handler = SIG_DFL;
136                 sigfillset(&sa.sa_mask);
137                 sa.sa_flags = 0;
138                 sigaction(sig, &sa, NULL);
139                 raise(exit_signal);
140         }
141
142         return;
143 }
144
145 #else
146
147 // While Windows has some very basic signal handling functions as required
148 // by C89, they are not really used, or so I understood. Instead, we use
149 // SetConsoleCtrlHandler() to catch user pressing C-c.
150
151 #include <windows.h>
152
153
154 static BOOL WINAPI
155 signal_handler(DWORD type lzma_attribute((unused)))
156 {
157         // Since we don't get a signal number which we could raise() at
158         // signals_exit() like on POSIX, just set the exit status to
159         // indicate an error, so that we cannot return with zero exit status.
160         set_exit_status(E_ERROR);
161         user_abort = true;
162         return TRUE;
163 }
164
165
166 extern void
167 signals_init(void)
168 {
169         if (!SetConsoleCtrlHandler(&signal_handler, TRUE))
170                 message_signal_handler();
171
172         return;
173 }
174
175 #endif