Import Upstream version 1.8.5
[hcoop/debian/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 AFS_UNREACHED(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 }