dd3db45c4e7f23791d2e0d6000ffc206139e84ed
[openafs.git] / src / util / softsig.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  *
9  * Portions Copyright (c) 2003 Apple Computer, Inc.
10  */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 #include <afs/param.h>
16 #include <assert.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #ifndef  AFS_NT40_ENV
20 #include <signal.h>
21 #include <unistd.h>
22 #else
23 #include <afs/procmgmt.h>
24 #endif
25 #include <pthread.h>
26
27 #include "pthread_nosigs.h"
28
29 /*------------------------------------------------------------------------
30  * Under Darwin 6.x (including 7.0), sigwait() is broken, so we use
31  * sigsuspend() instead.  We also don't block signals we don't know
32  * about, so they should kill us, rather than us returning zero status.
33  *------------------------------------------------------------------------*/
34
35 static pthread_t softsig_tid;
36 static struct {
37     void (*handler) (int);
38     int pending;
39 #if !(defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV)))
40     int fatal;
41 #endif /* !defined(AFS_DARWIN_ENV) || !defined(AFS_NBSD_ENV) */
42     int inited;
43 } softsig_sigs[NSIG];
44
45 static void *
46 softsig_thread(void *arg)
47 {
48     sigset_t ss, os;
49     int i;
50
51     sigemptyset(&ss);
52     /* get the list of signals _not_ blocked by AFS_SIGSET_CLEAR() */
53     pthread_sigmask(SIG_BLOCK, &ss, &os);
54     pthread_sigmask(SIG_SETMASK, &os, NULL);
55     sigaddset(&ss, SIGUSR1);
56 #if defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV))
57     pthread_sigmask (SIG_BLOCK, &ss, NULL);
58     sigdelset (&os, SIGUSR1);
59 #elif !defined(AFS_HPUX_ENV)
60     /* On HPUX, don't wait for 'critical' signals, as things such as
61      * SEGV won't cause a core, then. Some non-HPUX platforms may need
62      * this, though, since apparently if we wait on some signals but not
63      * e.g. SEGV, the softsig thread will still wait around when the
64      * other threads were killed by the SEGV. */
65     for (i = 0; i < NSIG; i++) {
66         if (!sigismember(&os, i) && i != SIGSTOP && i != SIGKILL) {
67             sigaddset(&ss, i);
68             softsig_sigs[i].fatal = 1;
69         }
70     }
71 #endif /* defined(AFS_DARWIN_ENV) || defined(AFS_NBSD_ENV) */
72
73     while (1) {
74         void (*h) (int);
75 #if !defined(AFS_DARWIN_ENV) && !defined(AFS_NBSD_ENV)
76         int sigw;
77 #endif
78
79         h = NULL;
80
81         for (i = 0; i < NSIG; i++) {
82             if (softsig_sigs[i].handler && !softsig_sigs[i].inited) {
83                 sigaddset(&ss, i);
84 #if defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV))
85                 pthread_sigmask (SIG_BLOCK, &ss, NULL);
86                 sigdelset (&os, i);
87 #endif /* defined(AFS_DARWIN_ENV) || defined(AFS_NBSD_ENV) */
88                 softsig_sigs[i].inited = 1;
89             }
90             if (softsig_sigs[i].pending) {
91                 softsig_sigs[i].pending = 0;
92                 h = softsig_sigs[i].handler;
93                 break;
94             }
95         }
96         if (i == NSIG) {
97 #if defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV))
98             sigsuspend (&os);
99 #else /* !defined(AFS_DARWIN_ENV) && !defined(AFS_NBSD_ENV) */
100             sigwait(&ss, &sigw);
101             if (sigw != SIGUSR1) {
102                 if (softsig_sigs[sigw].fatal)
103                     exit(0);
104                 softsig_sigs[sigw].pending = 1;
105             }
106 #endif /* defined(AFS_DARWIN_ENV) || defined(AFS_NBSD_ENV) */
107         } else if (h)
108             h(i);
109     }
110     return NULL;
111 }
112
113 static void
114 softsig_usr1(int signo)
115 {
116     signal (SIGUSR1, softsig_usr1);
117 }
118
119 void
120 softsig_init(void)
121 {
122     int rc;
123     AFS_SIGSET_DECL;
124     AFS_SIGSET_CLEAR();
125     rc = pthread_create(&softsig_tid, NULL, &softsig_thread, NULL);
126     assert(0 == rc);
127     AFS_SIGSET_RESTORE();
128     signal (SIGUSR1, softsig_usr1);
129 }
130
131 static void
132 softsig_handler(int signo)
133 {
134     signal(signo, softsig_handler);
135     softsig_sigs[signo].pending = 1;
136     pthread_kill(softsig_tid, SIGUSR1);
137 }
138
139 void
140 softsig_signal(int signo, void (*handler) (int))
141 {
142     softsig_sigs[signo].handler = handler;
143     softsig_sigs[signo].inited = 0;
144     signal(signo, softsig_handler);
145     pthread_kill(softsig_tid, SIGUSR1);
146 }
147
148 #if defined(TEST)
149 static void
150 print_foo(int signo)
151 {
152     printf("foo, signo = %d, tid = %d\n", signo, pthread_self());
153 }
154
155 int
156 main(int argc, char **argv)
157 {
158     softsig_init();
159     softsig_signal(SIGINT, print_foo);
160     printf("main is tid %d\n", pthread_self());
161     while (1)
162         sleep(60);
163 }
164 #endif