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