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