1 // Copyright 2012 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "utils/signals/interrupts.hpp"
40 #include "utils/sanity.hpp"
41 #include "utils/signals/exceptions.hpp"
42 #include "utils/signals/programmer.hpp"
44 namespace signals
= utils::signals
;
50 /// The interrupt signal that fired, or -1 if none.
51 static volatile int fired_signal
= -1;
54 /// Collection of PIDs.
55 typedef std::set
< pid_t
> pids_set
;
58 /// List of processes to kill upon reception of a signal.
59 static pids_set pids_to_kill
;
62 /// Programmer status for the SIGHUP signal.
63 static std::auto_ptr
< signals::programmer
> sighup_handler
;
64 /// Programmer status for the SIGINT signal.
65 static std::auto_ptr
< signals::programmer
> sigint_handler
;
66 /// Programmer status for the SIGTERM signal.
67 static std::auto_ptr
< signals::programmer
> sigterm_handler
;
70 /// Signal mask to restore after exiting a signal inhibited section.
71 static sigset_t old_sigmask
;
74 /// Whether there is an interrupts_handler object in existence or not.
75 bool interrupts_handler_active
= false;
78 /// Whether there is an interrupts_inhibiter object in existence or not.
79 bool interrupts_inhibiter_active
= false;
82 /// Generic handler to capture interrupt signals.
84 /// From this handler, we record that an interrupt has happened so that
85 /// check_interrupt() can know whether there execution has to be stopped or not.
86 /// We also terminate any of our child processes (started by the
87 /// utils::process::children class) so that any ongoing wait(2) system calls
90 /// \param signo The signal that caused this handler to be called.
92 signal_handler(const int signo
)
94 static const char* message
= "[-- Signal caught; please wait for "
96 if (::write(STDERR_FILENO
, message
, std::strlen(message
)) == -1) {
97 // We are exiting: the message printed here is only for informational
98 // purposes. If we fail to print it (which probably means something
99 // is really bad), there is not much we can do within the signal
100 // handler, so just ignore this.
103 fired_signal
= signo
;
105 for (pids_set::const_iterator iter
= pids_to_kill
.begin();
106 iter
!= pids_to_kill
.end(); ++iter
) {
107 // Redirecting the interrupt signal to our child processes does NOT
108 // guarantee that they also terminate. For that to happen, we'd need to
111 // *However*, because we use this code to invoke the kyua-testers only,
112 // and because we assume that such processes are well-behaved and
113 // terminate according to our expectations, we do it this way, which
114 // allows the testers to know which specific signal made them terminate.
115 (void)::kill(*iter
, signo
);
120 /// Installs signal handlers for potential interrupts.
122 /// \pre Must not have been called before.
123 /// \post The various sig*_handler global variables are atomically updated.
127 PRE(sighup_handler
.get() == NULL
);
128 PRE(sigint_handler
.get() == NULL
);
129 PRE(sigterm_handler
.get() == NULL
);
131 // Create the handlers on the stack first so that, if any of them fails, the
132 // stack unwinding cleans things up.
133 std::auto_ptr
< signals::programmer
> tmp_sighup_handler(
134 new signals::programmer(SIGHUP
, signal_handler
));
135 std::auto_ptr
< signals::programmer
> tmp_sigint_handler(
136 new signals::programmer(SIGINT
, signal_handler
));
137 std::auto_ptr
< signals::programmer
> tmp_sigterm_handler(
138 new signals::programmer(SIGTERM
, signal_handler
));
140 // Now, update the global pointers, which is an operation that cannot fail.
141 sighup_handler
= tmp_sighup_handler
;
142 sigint_handler
= tmp_sigint_handler
;
143 sigterm_handler
= tmp_sigterm_handler
;
147 /// Uninstalls the signal handlers installed by setup_handlers().
149 cleanup_handlers(void)
151 sighup_handler
->unprogram(); sighup_handler
.reset(NULL
);
152 sigint_handler
->unprogram(); sigint_handler
.reset(NULL
);
153 sigterm_handler
->unprogram(); sigterm_handler
.reset(NULL
);
158 /// Masks the signals installed by setup_handlers().
164 sigaddset(&mask
, SIGHUP
);
165 sigaddset(&mask
, SIGINT
);
166 sigaddset(&mask
, SIGTERM
);
167 #if defined(__minix) && !defined(NDEBUG)
169 #endif /* defined(__minix) && !defined(NDEBUG) */
170 ::sigprocmask(SIG_BLOCK
, &mask
, &old_sigmask
);
175 /// Resets the signal masking put in place by mask_signals().
179 #if defined(__minix) && !defined(NDEBUG)
181 #endif /* defined(__minix) && !defined(NDEBUG) */
182 ::sigprocmask(SIG_SETMASK
, &old_sigmask
, NULL
);
187 } // anonymous namespace
190 /// Constructor that sets up the signal handlers.
191 signals::interrupts_handler::interrupts_handler(void)
193 PRE(!interrupts_handler_active
);
195 interrupts_handler_active
= true;
199 /// Destructor that removes the signal handlers.
200 signals::interrupts_handler::~interrupts_handler(void)
203 interrupts_handler_active
= false;
207 /// Constructor that sets up signal masking.
208 signals::interrupts_inhibiter::interrupts_inhibiter(void)
210 PRE(!interrupts_inhibiter_active
);
212 interrupts_inhibiter_active
= true;
216 /// Destructor that removes signal masking.
217 signals::interrupts_inhibiter::~interrupts_inhibiter(void)
220 interrupts_inhibiter_active
= false;
224 /// Checks if an interrupt has fired.
226 /// Calls to this function should be sprinkled in strategic places through the
227 /// code protected by an interrupts_handler object.
229 /// \throw interrupted_error If there has been an interrupt.
231 signals::check_interrupt(void)
233 if (fired_signal
!= -1)
234 throw interrupted_error(fired_signal
);
238 /// Registers a child process to be killed upon reception of an interrupt.
240 /// \pre Must be called with interrupts being inhibited. The caller must ensure
241 /// that the call call to fork() and the addition of the PID happen atomically.
243 /// \param pid The PID of the child process. Must not have been yet regsitered.
245 signals::add_pid_to_kill(const pid_t pid
)
247 PRE(interrupts_inhibiter_active
);
248 PRE(pids_to_kill
.find(pid
) == pids_to_kill
.end());
249 pids_to_kill
.insert(pid
);
253 /// Unregisters a child process previously registered via add_pid_to_kill().
255 /// \pre Must be called with interrupts being inhibited. This is not necessary,
256 /// but pushing this to the caller simplifies our logic and provides consistency
257 /// with the add_pid_to_kill() call.
259 /// \param pid The PID of the child process. Must have been registered
260 /// previously, and the process must have already been awaited for.
262 signals::remove_pid_to_kill(const pid_t pid
)
264 PRE(interrupts_inhibiter_active
);
265 PRE(pids_to_kill
.find(pid
) != pids_to_kill
.end());
266 pids_to_kill
.erase(pid
);