chiark / gitweb /
Implement hooks for foreign select-using systems (currently not well
[mLib] / sig.c
... / ...
CommitLineData
1/* -*-c-*-
2 *
3 * $Id: sig.c,v 1.1 1999/07/26 23:16:26 mdw Exp $
4 *
5 * Signal handling
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * mLib is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with mLib; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: sig.c,v $
33 * Revision 1.1 1999/07/26 23:16:26 mdw
34 * Signal handling integrated into I/O system.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include <errno.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46#include <fcntl.h>
47
48#include "alloc.h"
49#include "fdflags.h"
50#include "report.h"
51#include "sel.h"
52#include "sig.h"
53
54/*----- Data structures ---------------------------------------------------*/
55
56typedef struct sigstate {
57 struct sigaction sa;
58 sig *list;
59} sigstate;
60
61/*----- Static variables --------------------------------------------------*/
62
63static sel_file sigsel;
64static int sigfd;
65static sigstate *sigs;
66
67/*----- Main code ---------------------------------------------------------*/
68
69/* --- @sig_handler@ --- *
70 *
71 * Arguments: @int n@ = signal number
72 *
73 * Returns: ---
74 *
75 * Use: Generic signal handler. Just writes a single byte to the
76 * signal pipe. The byte contains the signal number.
77 */
78
79static void sig_handler(int n)
80{
81 unsigned char sch = (unsigned char)n;
82 write(sigfd, &sch, 1);
83}
84
85/* --- @sig_read@ --- *
86 *
87 * Arguments: @int fd@ = file descriptor to read
88 * @unsigned mode@ = thing to do with descriptor
89 * @void *p@ = uninteresting argument
90 *
91 * Returns: ---
92 *
93 * Use: Dispatches signals to their handlers safely.
94 */
95
96static void sig_read(int fd, unsigned mode, void *p)
97{
98 sigset_t ss;
99 unsigned char buf[256];
100 int r;
101
102 sigemptyset(&ss);
103 while ((r = read(fd, buf, sizeof(buf))) > 0) {
104 unsigned char *p, *q;
105 for (p = buf, q = buf + r; p < q; p++) {
106 sig *s;
107 int n = *p;
108 if (sigismember(&ss, n))
109 continue;
110 sigaddset(&ss, n);
111 s = sigs[n].list;
112 while (s) {
113 sig *ss = s;
114 s = s->next;
115 ss->proc(n, ss->p);
116 }
117 }
118 }
119}
120
121/* --- @sig_add@ --- *
122 *
123 * Arguments: @sig *s@ = pointer to signal handler block
124 * @int n@ = number of the signal
125 * @void (*proc)(int n, void *p)@ = signal handler function
126 * @void *p@ = argument to pass to handler
127 *
128 * Returns: ---
129 *
130 * Use: Adds a signal handler.
131 */
132
133void sig_add(sig *s, int n, void (*proc)(int /*n*/, void */*p*/), void *p)
134{
135 sigstate *ss = &sigs[n];
136
137 /* --- Initialize the block --- */
138
139 s->proc = proc;
140 s->p = p;
141 s->sig = n;
142 s->next = ss->list;
143 s->prev = 0;
144
145 /* --- Engage a signal handler, maybe --- */
146
147 if (!ss->list) {
148 struct sigaction sa;
149 sa.sa_handler = sig_handler;
150 sa.sa_flags = SA_NOCLDSTOP;
151#ifdef SA_RESTART
152 sa.sa_flags |= SA_RESTART;
153#endif
154 sigemptyset(&sa.sa_mask);
155 sigaction(n, &sa, &ss->sa);
156 }
157
158 /* --- Link the block into the list --- */
159
160 if (ss->list)
161 ss->list->prev = s;
162 ss->list = s;
163}
164
165/* --- @sig_remove@ --- *
166 *
167 * Arguments: @sig *s@ = pointer to signal handler block
168 *
169 * Returns: ---
170 *
171 * Use: Removes the signal handler from the list.
172 */
173
174void sig_remove(sig *s)
175{
176 sigstate *ss = &sigs[s->sig];
177
178 /* --- Unlink the handler block --- */
179
180 if (s->next)
181 s->next->prev = s->prev;
182 if (s->prev)
183 s->prev->next = s->next;
184 else
185 ss->list = s->next;
186
187 /* --- Maybe remove the handler --- */
188
189 if (!ss->list)
190 sigaction(s->sig, &ss->sa, 0);
191}
192
193/* --- @sig_init@ --- *
194 *
195 * Arguments: @sel_state *s@ = pointer to select state
196 *
197 * Returns: ---
198 *
199 * Use: Initializes the signal handling system ready for use.
200 */
201
202void sig_init(sel_state *s)
203{
204 int fd[2];
205 unsigned nsig;
206
207 /* --- Work out how many signals there are --- */
208
209 {
210 sigset_t ss;
211 unsigned min = 0, max = 0;
212
213 sigemptyset(&ss);
214
215 /* --- Get a good upper bound --- *
216 *
217 * Cap the search at 256. I'll be sending signal numbers as bytes.
218 */
219
220 nsig = 1;
221 while (sigaddset(&ss, nsig) == 0) {
222 if (nsig == 256)
223 goto counted;
224 nsig <<= 1;
225 }
226
227 /* --- Now binary search until I find the actual limit --- */
228
229 min = nsig >> 1;
230 max = nsig;
231 for (;;) {
232 nsig = (min + max) >> 1;
233 if (nsig == min)
234 break;
235 if (sigaddset(&ss, nsig))
236 max = nsig;
237 else
238 min = nsig;
239 }
240 counted:;
241 }
242
243 /* --- Initialize the signal state table --- */
244
245 {
246 unsigned i;
247
248 sigs = xmalloc(nsig * sizeof(*sigs));
249 for (i = 0; i < nsig; i++)
250 sigs[i].list = 0;
251 }
252
253 /* --- Create the signal pipe --- */
254
255 if (pipe(fd))
256 die(1, "couldn't create pipe for signal handling");
257
258 /* --- Set both ends to nonblocking and close-on-exec --- */
259
260 fdflags(fd[0], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
261 fdflags(fd[1], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
262
263 /* --- Set everything up for the future --- */
264
265 sigfd = fd[1];
266 sel_initfile(s, &sigsel, fd[0], SEL_READ, sig_read, 0);
267 sel_addfile(&sigsel);
268}
269
270/*----- That's all, folks -------------------------------------------------*/