e3cbd53ab0b3b825a2449b908315741ace04d475
[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 }
63
64 static void *
65 signalHandler(void *arg)
66 {
67     int receivedSignal;
68     sigset_t set;
69
70     softsigSignalSet(&set);
71     while (1) {
72         opr_Verify(sigwait(&set, &receivedSignal) == 0);
73         opr_Verify(sigismember(&set, receivedSignal) == 1);
74         if (handlers[receivedSignal].handler != NULL) {
75             handlers[receivedSignal].handler(receivedSignal);
76         }
77     }
78     AFS_UNREACHED(return(NULL));
79 }
80
81 static void
82 ExitHandler(int signal)
83 {
84     sigset_t set;
85     sigemptyset(&set);
86     sigaddset(&set, signal);
87     pthread_sigmask(SIG_UNBLOCK, &set, NULL);
88     raise(signal);
89
90     /* Should be unreachable. */
91     exit(signal);
92 }
93
94 static void
95 StopHandler(int signal)
96 {
97     kill(getpid(), SIGSTOP);
98 }
99
100 /*!
101  * Register a soft signal handler
102  *
103  * Soft signal handlers may only be registered for async signals.
104  *
105  * @param[in] sig
106  *      The signal to register a handler for.
107  * @param[in] handler
108  *      The handler function to register, or NULL, to clear a signal handler.
109  *
110  * @returns
111  *      EINVAL if the signal given isn't one for which we can register a soft
112  *      handler.
113  */
114
115 int
116 opr_softsig_Register(int sig, void (*handler)(int))
117 {
118     sigset_t set;
119
120     softsigSignalSet(&set);
121
122     /* Check that the supplied signal is handled by softsig. */
123     if (sigismember(&set, sig)) {
124         handlers[sig].handler = handler;
125         return 0;
126     }
127
128     return EINVAL;
129 }
130
131 /*!
132  * Initialise the soft signal system
133  *
134  * This call initialises the soft signal system. It provides default handlers for
135  * SIGINT and SIGTSTP which preserve the operating system behaviour (terminating
136  * and stopping the process, respectively).
137  *
138  * opr_softsig_Init() must be called before any threads are created, as it sets
139  * up a global signal mask on the parent process that is then inherited by all
140  * children.
141  */
142
143 int
144 opr_softsig_Init(void)
145 {
146     sigset_t set;
147     pthread_t handlerThread;
148
149     /* Block all signals in the main thread, and in any threads which are created
150      * after us. Only the signal handler thread will receive signals. */
151     softsigSignalSet(&set);
152     pthread_sigmask(SIG_BLOCK, &set, NULL);
153
154     /* Register a few handlers so that we keep the usual behaviour for CTRL-C and
155      * CTRL-Z, unless the application replaces them. */
156     opr_Verify(opr_softsig_Register(SIGINT, ExitHandler) == 0);
157     opr_Verify(opr_softsig_Register(SIGTERM, ExitHandler) == 0);
158     opr_Verify(opr_softsig_Register(SIGQUIT, ExitHandler) == 0);
159     opr_Verify(opr_softsig_Register(SIGTSTP, StopHandler) == 0);
160
161     /*
162      * Some of our callers do actually specify a SIGFPE handler, but make sure
163      * the default SIGFPE behavior does actually terminate the process, in case
164      * we get a real FPE.
165      */
166     opr_Verify(opr_softsig_Register(SIGFPE, ExitHandler) == 0);
167
168     /* Create a signal handler thread which will respond to any incoming signals
169      * for us. */
170     opr_Verify(pthread_create(&handlerThread, NULL, signalHandler, NULL) == 0);
171     opr_Verify(pthread_detach(handlerThread) == 0);
172
173     return 0;
174 }