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