opr: Add new softsig implementation
[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     exit(signal);
86 }
87
88 static void
89 StopHandler(int signal)
90 {
91     kill(getpid(), SIGSTOP);
92 }
93
94 /*!
95  * Register a soft signal handler
96  *
97  * Soft signal handlers may only be registered for async signals.
98  *
99  * @param[in] sig
100  *      The signal to register a handler for.
101  * @param[in] handler
102  *      The handler function to register, or NULL, to clear a signal handler.
103  *
104  * @returns
105  *      EINVAL if the signal given isn't one for which we can register a soft
106  *      handler.
107  */
108
109 int
110 opr_softsig_Register(int sig, void (*handler)(int))
111 {
112     sigset_t set;
113
114     softsigSignalSet(&set);
115
116     /* Check that the supplied signal is handled by softsig. */
117     if (sigismember(&set, sig)) {
118         handlers[sig].handler = handler;
119         return 0;
120     }
121
122     return EINVAL;
123 }
124
125 /*!
126  * Initialise the soft signal system
127  *
128  * This call initialises the soft signal system. It provides default handlers for
129  * SIGINT and SIGTSTP which preserve the operating system behaviour (terminating
130  * and stopping the process, respectively).
131  *
132  * opr_softsig_Init() must be called before any threads are created, as it sets
133  * up a global signal mask on the parent process that is then inherited by all
134  * children.
135  */
136
137 int
138 opr_softsig_Init(void)
139 {
140     sigset_t set;
141     pthread_t handlerThread;
142
143     /* Block all signals in the main thread, and in any threads which are created
144      * after us. Only the signal handler thread will receive signals. */
145     softsigSignalSet(&set);
146     pthread_sigmask(SIG_BLOCK, &set, NULL);
147
148     /* Register a few handlers so that we keep the usual behaviour for CTRL-C and
149      * CTRL-Z, unless the application replaces them. */
150     opr_Verify(opr_softsig_Register(SIGINT, ExitHandler) == 0);
151     opr_Verify(opr_softsig_Register(SIGTERM, ExitHandler) == 0);
152     opr_Verify(opr_softsig_Register(SIGQUIT, ExitHandler) == 0);
153     opr_Verify(opr_softsig_Register(SIGTSTP, StopHandler) == 0);
154
155     /* Create a signal handler thread which will respond to any incoming signals
156      * for us. */
157     opr_Verify(pthread_create(&handlerThread, NULL, signalHandler, NULL) == 0);
158     opr_Verify(pthread_detach(handlerThread) == 0);
159
160     return 0;
161 }