1 // -*- c++ -*-
2 //------------------------------------------------------------------------------
3 //                            SigAction.h
4 //------------------------------------------------------------------------------
5 //  Copyright (c) 1997 by Vladislav Grinchenko
6 //
7 //  This library is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU Library General Public
9 //  License as published by the Free Software Foundation; either
10 //  version 2 of the License, or (at your option) any later version.
11 //------------------------------------------------------------------------------
12 
13 #ifndef _SigAction_h
14 #define _SigAction_h
15 
16 // System includes
17 //
18 #include <signal.h>
19 #include <errno.h>
20 
21 #include "assa/Assure.h"
22 #include "assa/SigSet.h"
23 
24 // some convenient typedefs
25 //
26 extern "C" {
27 typedef struct sigaction SIGACTION;
28 typedef void (*C_SIG_HANDLER)( int );
29 }
30 
31 namespace ASSA {
32 
33 #if !defined(WIN32)
34 
35 /** @file SigAction.h
36 
37 SigAction is a C++ wrapper around sigaction structure
38 
39 Class SigAction implements a C++ wrapper around
40 struct sigaction. It class also provides a range of all possible
41 operation that can be performed on it, including sigaction(2) system call.
42 
43 struct sigaction is defined as:
44 
45 <pre>
46    struct sigaction {
47        void      (*sa_handler) ();
48        sigset_t  sa_mask;
49        int       sa_flags;
50        void      (*sa_sigaction) (int, siginfo_t*, void*);
51    };
52 </pre>
53 
54 It is used to set all the details of what your process should do when
55 a signal arrives. It encapsulates the action to be taken on receipt
56 of a particular signal.
57 
58 The most important member is sa_handler, which takes a pointer
59 to a function. This function will be invoked whenever the process gets
60 a particular POSIX.1 signal.
61 
62 Some of the member function of SigAction class take a parameter
63 of type C_SIG_HANDLER.
64 
65 It can be one of:
66    - "C" signal handling function (sa_handler above):\n
67       void sig_handler (int signum)
68    - SIG_ERR
69    - SIG DFL takes default signal action when caught
70    - SIG_IGN ignores signal (for those that can be ignored)
71 
72 The sa_mask mask for the signal action specifies a set of signals
73 to be blocked while the signal handler is active.
74 On the entry into the signal handler,
75 that set of signals is added to a set of signals already being
76 blocked from delivery when the signal is delivered to the process.
77 In addition, the signal that caused the handler to be executed will also
78 be blocked (SIGSTOP and SIGKILL cannot be blocked - this is enforced
79 by the underlying OS).
80 
81 Flags sa_flags in the set of flags ORed that allows to modify
82 the delivery of the signal.
83 POSIX.1 spec. defines only SA_NOCLDSTOP flag. All other
84 flags are system-dependent. Consult your local sigaction(2)
85 man page for details.
86 
87 Because SigAction is a wrapper around sigaction(2),
88 after sig_handler returns (and before anything else), the OS
89 will reinstall current disposition for the signal. To reset signal's
90 disposition to SIG_DFL, SUN Solaris OS uses flag SA_RESETHAND, and Linux OS
91 uses SA_ONESHOT.
92 */
93 
94 class SigAction
95 {
96 public:
97 	/** Default constructor creates SigAction object
98 	    with null-action.
99 	*/
100 	SigAction();
101 
102 	/** Construct a SigAction object with "C" signal
103 	    handler function. This constructor doesn't install any
104 	    actions - it is merely a shell for actiono to be installed
105 	    for any signal(s). Thus, you can reuse the same object for
106 	    number of differen signals.
107 
108 	    @param handler_ "C" signal handler function to call.
109 	    @param sig_mask_ Set of signals to block while handler_
110 	    is active.
111 	    @param flags_ Controls behavior of signal handler (OS-specific:
112 	    see Available Options: section of documentation).
113 	*/
114 	SigAction (C_SIG_HANDLER handler_,
115 			   SigSet*       sig_mask_ = 0,
116 			   int           flags_ = 0);
117 
118 	/** Construct a SigAction with "C" signal handler function
119 	    and change program's disposition for signum_
120 	    immediately.<p>
121 	    First argument is the "C" function. It cannot be a non-static
122 	    C++ class member function. This function pretty much simulates
123 	    C-like approach the the signal handling. For C++ member
124 	    function approach, see SigHandler & Co.
125 
126 	    @param handler_ "C" signal handler function to call.
127 	    @param signum_  Signal which disposition is to change.
128 	    @param sig_mask_ Set of signals to block while handler_
129 	    is active.
130 	    @param flags_ Controls behavior of signal handler (OS-specific:
131 	    see Available Options: section of documentation).
132 	*/
133 	SigAction (C_SIG_HANDLER handler_,
134 			   int           signum_,
135 			   SigSet*       sig_mask_ = 0,
136 			   int           flags_ = 0);
137 
138 	/** Register this object as current disposition for signal
139 	    signum_, and store old disposition in oaction_,
140 	    if not NULL. This function installs C_SIG_HANDLER this
141 	    object represents, thus simulating C-like approach to signal
142 	    handling.
143 
144 	    @param signum_ Signal which disposition to install.
145 	    @param oaction_ Placeholder for the old disposition.
146 	    @return 0 on success, -1 on error, with errno indicating
147 	    the error.
148 	*/
149 	int register_action (int signum_, SigAction* oaction_ = 0);
150 
151 	/** Change object's disposition to oaction_, and install
152 	    it as current disposition for the signal signum_.
153 
154 	    @param signum_ Signal which disposition to restore.
155 	    @param oaction_ Disposition to restore.
156 	    @return 0 on success, -1 on error, with errno indicating
157 	    the error.
158 	*/
159 	int restore_action (int signum_, SigAction& oaction_);
160 
161 	/** Retrieve current disposition for the signal signum_
162 	    into this object.
163 	    @param signum_ Signal number
164 	    @return 0 on success, -1 on error, with errno indicating
165 	    the error.
166 	*/
167 	int retrieve_action (int signum_);
168 
169 	/** Set sigaction structure to sa_
170 	    @param sa_ New value for internal struct sigaction.
171 	*/
172 	void action (SIGACTION * sa_);
173 
174 	/** Retrieve current sigaction.
175 	    @return Pointer to an internal struct sigaction.
176 	*/
177 	SIGACTION * action ();
178 
179 	/** Set signal flags to new_flags_.
180 	    @param new_flags_ New flags for this action.
181 	*/
182 	void flags (int new_flags_);
183 
184 	/** Retrieve current flags.
185 	    @return Value of current flags for this action.
186 	*/
187 	int flags ();
188 
189 	/** Set new signal mask mask_set_.
190 	 */
191 	void mask (SigSet & mask_set_);
192 
193 	/** Retrieve current signal mask.
194 	 */
195 	SigSet mask ();
196 
197 	/** Set new signal handler to function pointer sha_.
198 	 */
199 	void handler (C_SIG_HANDLER sha_);
200 
201 	/** Retrieve current signal handler function.
202 	 */
203 	C_SIG_HANDLER handler ();
204 
205 	/** Conversion operator that converts SigAction to a
206 	    pointer to the internal struct sigaction data
207 	    member for direct use with C-library functions.
208 	*/
209 	operator SIGACTION *();
210 
211 private:
212 	/// sigaction structure itself
213 	SIGACTION m_sa;
214 };
215 
216 //-------------------------------------------------------------------------
217 //------------------------Inline functions---------------------------------
218 //-------------------------------------------------------------------------
219 inline
220 SigAction::
SigAction()221 SigAction ()
222 {
223 	trace_with_mask("SigAction::SigAction", SIGACT);
224 
225 	m_sa.sa_flags = 0;
226 	sigemptyset(&m_sa.sa_mask);
227 	*(C_SIG_HANDLER*) &m_sa.sa_handler = (C_SIG_HANDLER) 0;
228 }
229 
230 inline
231 SigAction::
SigAction(C_SIG_HANDLER handler_,SigSet * sig_mask_,int flags_)232 SigAction (C_SIG_HANDLER handler_,
233 					  SigSet*       sig_mask_,
234 					  int           flags_)
235 {
236 	trace_with_mask("SigAction::SigAction(,,)", SIGACT);
237 
238 	m_sa.sa_flags = flags_;
239 	if (sig_mask_ == NULL) {
240 		sigemptyset(&m_sa.sa_mask);
241 	}
242 	else {
243 		/*---
244 		  here, suppose to do bitwise structure assignment,
245 		  but does it really do so?
246 		  = *sig_mask_
247 		     = *(sig_mask_.operator *())
248 		        = *(SigSet *tmp = &sig_mask_.m_sa) ????
249 		---*/
250 		m_sa.sa_mask = **sig_mask_;
251 	}
252 	*(C_SIG_HANDLER*) &m_sa.sa_handler = (C_SIG_HANDLER) handler_;
253 }
254 
255 inline
256 SigAction::
SigAction(C_SIG_HANDLER handler_,int signum_,SigSet * sig_mask_,int flags_)257 SigAction (C_SIG_HANDLER handler_,
258 		   int           signum_,
259 		   SigSet*       sig_mask_,
260 		   int           flags_)
261 {
262 	trace_with_mask("SigAction::SigAction(,,,)", SIGACT);
263 
264 	m_sa.sa_flags = flags_;
265 	if (sig_mask_ == NULL) {
266 		sigemptyset(&m_sa.sa_mask);
267 	}
268 	else {
269 		/*---  same problem as above... ---*/
270 		m_sa.sa_mask = **sig_mask_;
271 	}
272 	*(C_SIG_HANDLER*) &m_sa.sa_handler = (C_SIG_HANDLER) handler_;
273 
274 	/*--- installing disposition... ---*/
275 	sigaction (signum_, &m_sa, 0);
276 }
277 
278 inline void
279 SigAction::
action(SIGACTION * sa_)280 action (SIGACTION* sa_)
281 {
282 	trace_with_mask("SigAction::action", SIGACT);
283 	m_sa = *sa_;
284 }
285 
286 inline SIGACTION *
287 SigAction::
action()288 action ()
289 {
290 	trace_with_mask("SigAction::action", SIGACT);
291 
292 	return &m_sa;
293 }
294 
295 inline void
296 SigAction::
flags(int new_flags_)297 flags (int new_flags_)
298 {
299 	trace_with_mask("void SigAction::flags()", SIGACT);
300 
301 	m_sa.sa_flags = new_flags_;
302 }
303 
304 inline int
305 SigAction::
flags()306 flags ()
307 {
308 	trace_with_mask("int SigAction::flags()", SIGACT);
309 
310 	return m_sa.sa_flags;
311 }
312 
313 inline void
314 SigAction::
mask(SigSet & mask_set_)315 mask (SigSet & mask_set_)
316 {
317 	trace_with_mask("void SigAction::mask()", SIGACT);
318 
319 	m_sa.sa_mask = *mask_set_;
320 }
321 
322 inline SigSet
323 SigAction::
mask()324 mask ()
325 {
326 	trace_with_mask("SigSet SigAction::mask()", SIGACT);
327 
328 	SigSet tmpset(&m_sa.sa_mask);
329 	return tmpset;
330 }
331 
332 inline void
333 SigAction::
handler(C_SIG_HANDLER sha_)334 handler (C_SIG_HANDLER sha_)
335 {
336 	trace_with_mask("void SigAction::handler()", SIGACT);
337 
338 	*(C_SIG_HANDLER*) &m_sa.sa_handler = (C_SIG_HANDLER) sha_;
339 }
340 
341 inline C_SIG_HANDLER
342 SigAction::
handler()343 handler ()
344 {
345 	trace_with_mask("C_SIG_HANDLER SigAction::handler()", SIGACT);
346 
347 	return (C_SIG_HANDLER) m_sa.sa_handler;
348 }
349 
350 inline
351 SigAction::operator SIGACTION * ()
352 {
353 	trace_with_mask("SigAction::operator SIGACTION * ()", SIGACT);
354 
355 	return &m_sa;
356 }
357 
358 inline int
359 SigAction::
register_action(int signum_,SigAction * oaction_)360 register_action (int signum_, SigAction* oaction_)
361 {
362 	trace_with_mask("SigAction::register_action()", SIGACT);
363 
364 	/*--- place here recursive mutex lock to guard ... ---*/
365 	struct sigaction *osa = oaction_ == 0 ? 0 : oaction_->action();
366 	return sigaction(signum_, &m_sa, osa);
367 }
368 
369 inline int
370 SigAction::
restore_action(int signum_,SigAction & oaction_)371 restore_action (int signum_, SigAction& oaction_)
372 {
373 	trace_with_mask("SigAction::restore_action()", SIGACT);
374 
375 	m_sa = *oaction_.action();
376 	return sigaction(signum_, &m_sa, 0);
377 }
378 
379 inline int
380 SigAction::
retrieve_action(int signum_)381 retrieve_action (int signum_)
382 {
383 	trace_with_mask("SigAction::retrieve_action()", SIGACT);
384 
385 	return sigaction(signum_, 0, &m_sa);
386 }
387 
388 #endif // !defined(WIN32)
389 
390 } // end namespace ASSA
391 
392 
393 #endif /* _SigAction_h */
394