2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Written by Chris Rankin, rankinc@zipworld.com.au
27 #include "fvwmsignal.h"
33 typedef enum { SIG_INIT
=0, SIG_DONE
} SIG_STATUS
;
35 volatile sig_atomic_t isTerminated
= false;
37 static volatile sig_atomic_t canJump
= false;
39 static sigjmp_buf deadJump
;
40 #define SIGSETJMP(env, savesigs) sigsetjmp(env, savesigs)
42 static jmp_buf deadJump
;
43 #define SIGSETJMP(env, savesigs) setjmp(env)
45 #if defined(HAVE_SIGLONGJMP) && defined(HAVE_SIGSETJMP)
46 #define SIGLONGJMP(env, val) siglongjmp(env, val)
48 #define SIGLONGJMP(env, val) longjmp(env, val)
51 * Reap child processes, preventing them from becoming zombies.
52 * We do this asynchronously within the SIGCHLD handler so that
56 fvwmReapChildren(int sig
)
62 * This is a signal handler, AND SO MUST BE REENTRANT!
63 * Now the wait() functions are safe here, but please don't
64 * add anything unless you're SURE that the new functions
65 * (plus EVERYTHING they call) are also reentrant. There
66 * are very few functions which are truly safe.
69 while (waitpid(-1, NULL
, WNOHANG
) > 0)
71 /* nothing to do here */
74 while (wait3(NULL
, WNOHANG
, NULL
) > 0)
76 /* nothing to do here */
79 # error One of waitpid or wait3 is needed.
86 #ifdef USE_BSD_SIGNALS
90 * fvwmSetSignalMask - store the set of mutually exclusive signals
91 * away for future reference. This prevents different signals from
92 * trying to access the same static data at the same time.
94 * NOTE: We don't need this if we have POSIX.1 since we can install
95 * a signal mask automatically using sigaction()
98 fvwmSetSignalMask(int sigmask
)
105 * fvwmGetSignalMask - get the set of signals that will terminate fvwm
107 * NOTE: We don't need this if we have POSIX.1 since we can install
108 * a signal mask automatically using sigaction()
111 fvwmGetSignalMask(void)
120 * fvwmSetTerminate - set the "end-of-execution" flag.
121 * This function should ONLY be called at the end of a
122 * signal handler. It is an integral part of the mechanism
123 * to stop system calls from blocking once the process is
126 * NOTE: This is NOT a signal handler function in its own right!
129 fvwmSetTerminate(int sig
)
140 * This non-local jump is safe ONLY because we haven't called
141 * any non-reentrant functions in the short period where the
142 * "canJump" variable is true.
144 * NOTE: No need to restore the signal mask, since siglongjmp
145 * is designed to do that for us.
147 SIGLONGJMP(deadJump
, SIG_DONE
);
156 * fvwmSelect - wrapper around the select() system call.
157 * This system call may block indefinitely. We don't want
158 * to block at all if the "terminate" flag is set - we
159 * just want it to fail as quickly as possible.
162 fvwmSelect(fd_set_size_t nfds
,
163 fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
164 struct timeval
*timeout
)
166 volatile int iRet
= -1; /* This variable MUST NOT be in a register */
169 /* If we're using the C version of alloca, see if anything needs to be
176 * Yes, we trash errno here, but you're only supposed to check
177 * errno immediately after a function fails anyway. If we fail,
178 * then it's because we received a signal. If we succeed, we
179 * shouldn't be checking errno. And if somebody calls us expecting
180 * us to preserve errno then that's their bug.
182 * NOTE: We mustn't call any function that might trash errno
183 * ourselves, except select() itself of course. I believe
184 * that sigsetjmp() does NOT trash errno.
189 * Now initialise the non-local jump. Between here and the end of
190 * the routine (more-or-less) we must NOT call any non-reentrant
191 * functions! This is because we might need to abandon them half
192 * way through execution and return here!
194 if ( SIGSETJMP(deadJump
, 1) == SIG_INIT
)
197 * Activate the non-local jump. Between now and when we turn the
198 * jump off again, we must NOT call any non-reentrant functions
199 * because we could be interrupted halfway through ...
204 * If we have already been told to terminate then we will not
205 * execute the select() because the flag will be set. If a
206 * "terminate" signal arrives between testing the flag and
207 * calling select() then we will jump back to the non-local
213 * The "die" signal will interrupt this system call:
214 * that IS the whole point, after all :-)
217 SELECT_FD_SET_CAST readfds
,
218 SELECT_FD_SET_CAST writefds
,
219 SELECT_FD_SET_CAST exceptfds
,
224 * The non-local jump is about to go out of scope,
225 * so we must deactivate it. Note that the return-
226 * value from select() will be safely stored in the
227 * local variable before the jump is disabled.
235 #endif /* HAVE_SELECT */