]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/xz/src/xz/signals.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / xz / 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 /// True once signals_init() has finished. This is used to skip blocking
31 /// signals (with uninitialized hooked_signals) if signals_block() and
32 /// signals_unblock() are called before signals_init() has been called.
33 static bool signals_are_initialized = false;
34
35 /// signals_block() and signals_unblock() can be called recursively.
36 static size_t signals_block_count = 0;
37
38
39 static void
40 signal_handler(int sig)
41 {
42         exit_signal = sig;
43         user_abort = true;
44         return;
45 }
46
47
48 extern void
49 signals_init(void)
50 {
51         // List of signals for which we establish the signal handler.
52         static const int sigs[] = {
53                 SIGINT,
54                 SIGTERM,
55 #ifdef SIGHUP
56                 SIGHUP,
57 #endif
58 #ifdef SIGPIPE
59                 SIGPIPE,
60 #endif
61 #ifdef SIGXCPU
62                 SIGXCPU,
63 #endif
64 #ifdef SIGXFSZ
65                 SIGXFSZ,
66 #endif
67         };
68
69         // Mask of the signals for which we have established a signal handler.
70         sigemptyset(&hooked_signals);
71         for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
72                 sigaddset(&hooked_signals, sigs[i]);
73
74         struct sigaction sa;
75
76         // All the signals that we handle we also blocked while the signal
77         // handler runs.
78         sa.sa_mask = hooked_signals;
79
80         // Don't set SA_RESTART, because we want EINTR so that we can check
81         // for user_abort and cleanup before exiting. We block the signals
82         // for which we have established a handler when we don't want EINTR.
83         sa.sa_flags = 0;
84         sa.sa_handler = &signal_handler;
85
86         for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
87                 // If the parent process has left some signals ignored,
88                 // we don't unignore them.
89                 struct sigaction old;
90                 if (sigaction(sigs[i], NULL, &old) == 0
91                                 && old.sa_handler == SIG_IGN)
92                         continue;
93
94                 // Establish the signal handler.
95                 if (sigaction(sigs[i], &sa, NULL))
96                         message_signal_handler();
97         }
98
99         signals_are_initialized = true;
100
101         return;
102 }
103
104
105 #ifndef __VMS
106 extern void
107 signals_block(void)
108 {
109         if (signals_are_initialized) {
110                 if (signals_block_count++ == 0) {
111                         const int saved_errno = errno;
112                         mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL);
113                         errno = saved_errno;
114                 }
115         }
116
117         return;
118 }
119
120
121 extern void
122 signals_unblock(void)
123 {
124         if (signals_are_initialized) {
125                 assert(signals_block_count > 0);
126
127                 if (--signals_block_count == 0) {
128                         const int saved_errno = errno;
129                         mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL);
130                         errno = saved_errno;
131                 }
132         }
133
134         return;
135 }
136 #endif
137
138
139 extern void
140 signals_exit(void)
141 {
142         const int sig = exit_signal;
143
144         if (sig != 0) {
145                 struct sigaction sa;
146                 sa.sa_handler = SIG_DFL;
147                 sigfillset(&sa.sa_mask);
148                 sa.sa_flags = 0;
149                 sigaction(sig, &sa, NULL);
150                 raise(exit_signal);
151         }
152
153         return;
154 }
155
156 #else
157
158 // While Windows has some very basic signal handling functions as required
159 // by C89, they are not really used, or so I understood. Instead, we use
160 // SetConsoleCtrlHandler() to catch user pressing C-c.
161
162 #include <windows.h>
163
164
165 static BOOL WINAPI
166 signal_handler(DWORD type lzma_attribute((unused)))
167 {
168         // Since we don't get a signal number which we could raise() at
169         // signals_exit() like on POSIX, just set the exit status to
170         // indicate an error, so that we cannot return with zero exit status.
171         //
172         // FIXME: Since this function runs in its own thread,
173         // set_exit_status() should have a mutex.
174         set_exit_status(E_ERROR);
175         user_abort = true;
176         return TRUE;
177 }
178
179
180 extern void
181 signals_init(void)
182 {
183         if (!SetConsoleCtrlHandler(&signal_handler, TRUE))
184                 message_signal_handler();
185
186         return;
187 }
188
189 #endif