1 /*
2 * Copyright (C) 2003 Sam Horrocks
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20 #include "speedy.h"
21
22 /*
23 * Signal handling routines
24 */
25
26 static volatile int got_sig[SPEEDY_MAXSIG];
27 static sigset_t blockall_save;
28 static int all_blocked;
29
speedy_sig_blockall(void)30 void speedy_sig_blockall(void) {
31 sigset_t full_set;
32
33 sigfillset(&full_set);
34 sigprocmask(SIG_BLOCK, &full_set, &blockall_save);
35 all_blocked = 1;
36 }
37
speedy_sig_blockall_undo(void)38 void speedy_sig_blockall_undo(void) {
39 sigprocmask(SIG_SETMASK, &blockall_save, NULL);
40 all_blocked = 0;
41 }
42
sig_find(const volatile int sig_rcvd[SPEEDY_MAXSIG],int sig)43 static int sig_find(const volatile int sig_rcvd[SPEEDY_MAXSIG], int sig) {
44 register int i;
45
46 for (i = 0; i < SPEEDY_MAXSIG && sig_rcvd[i]; ++i) {
47 if (sig_rcvd[i] == sig)
48 return -1;
49 }
50 return i;
51 }
52
sig_handler(int sig)53 static void sig_handler(int sig) {
54 int i;
55
56 if ((i = sig_find(got_sig, sig)) >= 0 && i < SPEEDY_MAXSIG) {
57 got_sig[i++] = sig;
58 if (i < SPEEDY_MAXSIG)
59 got_sig[i] = 0;
60 }
61 }
62
sig_wait_basic(const SigList * sl)63 static void sig_wait_basic(const SigList *sl) {
64 for (got_sig[0] = 0; !got_sig[0];)
65 sigsuspend(&sl->unblock_sigs);
66 }
67
speedy_sig_wait(SigList * sl)68 void speedy_sig_wait(SigList *sl) {
69 sig_wait_basic(sl);
70 speedy_util_time_invalidate();
71 speedy_memcpy(sl->sig_rcvd, got_sig, sizeof(got_sig));
72 }
73
speedy_sig_got(const SigList * sl,int sig)74 int speedy_sig_got(const SigList *sl, int sig) {
75 return sig_find(sl->sig_rcvd, sig) == -1;
76 }
77
sig_init2(SigList * sl,int how)78 static void sig_init2(SigList *sl, int how) {
79 int i;
80
81 /* Set up handlers and save old action setting */
82 {
83 struct sigaction sigact;
84 sigact.sa_handler = &sig_handler;
85 sigact.sa_flags = 0;
86 sigemptyset(&sigact.sa_mask);
87 for (i = 0; i < sl->numsigs; ++i)
88 sigaction(sl->signum[i], &sigact, &(sl->sigact_save[i]));
89 }
90
91 /* Block or unblock our signals. Save original mask */
92 if (all_blocked) {
93 sl->sigset_save = blockall_save;
94 for (i = 0; i < sl->numsigs; ++i) {
95 if (how == SIG_BLOCK)
96 sigaddset(&blockall_save, sl->signum[i]);
97 else
98 sigdelset(&blockall_save, sl->signum[i]);
99 }
100 } else {
101 sigset_t block_sigs;
102 sigemptyset(&block_sigs);
103 for (i = 0; i < sl->numsigs; ++i)
104 sigaddset(&block_sigs, sl->signum[i]);
105 sigprocmask(how, &block_sigs, &sl->sigset_save);
106 }
107
108 /* Make an unblock mask for our signals */
109 sl->unblock_sigs = sl->sigset_save;
110 for (i = 0; i < sl->numsigs; ++i)
111 sigdelset(&sl->unblock_sigs, sl->signum[i]);
112 }
113
speedy_sig_init(SigList * sl,const int * sigs,int numsigs,int how)114 void speedy_sig_init(SigList *sl, const int *sigs, int numsigs, int how) {
115
116 /* Copy in args */
117 if (numsigs > SPEEDY_MAXSIG)
118 DIE_QUIET("Too many sigs passed to sig_init");
119 speedy_memcpy(sl->signum, sigs, numsigs * sizeof(int));
120 sl->numsigs = numsigs;
121
122 /* Finish init */
123 sig_init2(sl, how);
124 }
125
speedy_sig_free(const SigList * sl)126 void speedy_sig_free(const SigList *sl) {
127 int i;
128
129 /* Get rid of any pending signals. On Sun/apache-2 we don't get pending
130 * signals as soon as they are unblocked - instead they get delivered
131 * after the action is restored, which is not what we want.
132 */
133 do {
134 sigset_t set;
135
136 /* Bug in Mac OS X 10.1 and earlier - sigpending is essentially a
137 * no-op, so we get garbage, and get stuck in sigsuspend.
138 * Workaround by clearing out the set initially so we get no pending
139 * signals back.
140 */
141 sigemptyset(&set);
142
143 if (sigpending(&set) == -1)
144 break;
145 for (i = 0; i < sl->numsigs; ++i) {
146 if (sigismember(&set, sl->signum[i])) {
147 sig_wait_basic(sl);
148 break;
149 }
150 }
151 } while (i < sl->numsigs);
152
153 /* Unblock sigs */
154 if (all_blocked)
155 blockall_save = sl->sigset_save;
156 else
157 sigprocmask(SIG_SETMASK, &sl->sigset_save, NULL);
158
159 /* Install old handlers */
160 for (i = 0; i < sl->numsigs; ++i)
161 sigaction(sl->signum[i], &(sl->sigact_save[i]), NULL);
162 }
163