opr: Avoid sigwait on SIGWAITING
[openafs.git] / src / opr / softsig.c
1 /*
2  * Copyright (c) 2010 Your File System Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 /* Soft signals
26  *
27  * This is a pthread compatible signal handling system. It doesn't have any
28  * restrictions on the code which can be called from a signal handler, as handlers
29  * are processed in a dedicated thread, rather than as part of the async signal
30  * handling code.
31  *
32  * Applications wishing to use this system must call opr_softsig_Init _before_
33  * starting any other threads. After this, all signal handlers must be registered
34  * using opr_softsig_Register.
35  */
36
37 #include <afsconfig.h>
38 #include <afs/param.h>
39
40 #include <opr.h>
41 #include <roken.h>
42
43 #include <pthread.h>
44
45 static struct {
46     void (*handler) (int);
47 } handlers[NSIG];
48
49 static void
50 softsigSignalSet(sigset_t *set)
51 {
52     sigfillset(set);
53     sigdelset(set, SIGKILL);
54     sigdelset(set, SIGSTOP);
55     sigdelset(set, SIGCONT);
56     sigdelset(set, SIGABRT);
57     sigdelset(set, SIGBUS);
58     sigdelset(set, SIGILL);
59     sigdelset(set, SIGPIPE);
60     sigdelset(set, SIGSEGV);
61     sigdelset(set, SIGTRAP);
62 #ifdef AFS_AIX_ENV
63     sigdelset(set, SIGWAITING);
64 #endif
65 }
66
67 static void *
68 signalHandler(void *arg)
69 {
70     int receivedSignal;
71     sigset_t set;
72
73     softsigSignalSet(&set);
74     while (1) {
75         opr_Verify(sigwait(&set, &receivedSignal) == 0);
76         opr_Verify(sigismember(&set, receivedSignal) == 1);
77         if (handlers[receivedSignal].handler != NULL) {
78             handlers[receivedSignal].handler(receivedSignal);
79         }
80     }
81     AFS_UNREACHED(return(NULL));
82 }
83
84 static void
85 ExitHandler(int signal)
86 {
87     sigset_t set;
88     sigemptyset(&set);
89     sigaddset(&set, signal);
90     pthread_sigmask(SIG_UNBLOCK, &set, NULL);
91     raise(signal);
92
93     /* Should be unreachable. */
94     exit(signal);
95 }
96
97 static void
98 StopHandler(int signal)
99 {
100     kill(getpid(), SIGSTOP);
101 }
102
103 /*!
104  * Register a soft signal handler
105  *
106  * Soft signal handlers may only be registered for async signals.
107  *
108  * @param[in] sig
109  *      The signal to register a handler for.
110  * @param[in] handler
111  *      The handler function to register, or NULL, to clear a signal handler.
112  *
113  * @returns
114  *      EINVAL if the signal given isn't one for which we can register a soft
115  *      handler.
116  */
117
118 int
119 opr_softsig_Register(int sig, void (*handler)(int))
120 {
121     sigset_t set;
122
123     softsigSignalSet(&set);
124
125     /* Check that the supplied signal is handled by softsig. */
126     if (sigismember(&set, sig)) {
127         handlers[sig].handler = handler;
128         return 0;
129     }
130
131     return EINVAL;
132 }
133
134 /*!
135  * Initialise the soft signal system
136  *
137  * This call initialises the soft signal system. It provides default handlers for
138  * SIGINT and SIGTSTP which preserve the operating system behaviour (terminating
139  * and stopping the process, respectively).
140  *
141  * opr_softsig_Init() must be called before any threads are created, as it sets
142  * up a global signal mask on the parent process that is then inherited by all
143  * children.
144  */
145
146 int
147 opr_softsig_Init(void)
148 {
149     sigset_t set;
150     pthread_t handlerThread;
151
152     /* Block all signals in the main thread, and in any threads which are created
153      * after us. Only the signal handler thread will receive signals. */
154     softsigSignalSet(&set);
155     pthread_sigmask(SIG_BLOCK, &set, NULL);
156
157     /* Register a few handlers so that we keep the usual behaviour for CTRL-C and
158      * CTRL-Z, unless the application replaces them. */
159     opr_Verify(opr_softsig_Register(SIGINT, ExitHandler) == 0);
160     opr_Verify(opr_softsig_Register(SIGTERM, ExitHandler) == 0);
161     opr_Verify(opr_softsig_Register(SIGQUIT, ExitHandler) == 0);
162     opr_Verify(opr_softsig_Register(SIGTSTP, StopHandler) == 0);
163
164     /*
165      * Some of our callers do actually specify a SIGFPE handler, but make sure
166      * the default SIGFPE behavior does actually terminate the process, in case
167      * we get a real FPE.
168      */
169     opr_Verify(opr_softsig_Register(SIGFPE, ExitHandler) == 0);
170
171     /* Create a signal handler thread which will respond to any incoming signals
172      * for us. */
173     opr_Verify(pthread_create(&handlerThread, NULL, signalHandler, NULL) == 0);
174     opr_Verify(pthread_detach(handlerThread) == 0);
175
176     return 0;
177 }