5 * (c) 1999 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * mLib is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
42 /*----- Data structures ---------------------------------------------------*/
44 typedef struct sigstate {
49 /*----- Static variables --------------------------------------------------*/
51 static sel_file sigsel;
53 static sigstate *sigs;
54 static sigset_t ss_all, ss_caught;
57 /*----- Main code ---------------------------------------------------------*/
59 /* --- @sig_handler@ --- *
61 * Arguments: @int n@ = signal number
65 * Use: Generic signal handler. Writes a single byte to the
66 * signal pipe. The byte contains the signal number. Also
67 * sets the appropriate bit in @ss_caught@ to indicate which
68 * signals are pending.
71 static void sig_handler(int n)
74 unsigned char sch = (unsigned char)n;
75 sigprocmask(SIG_BLOCK, &ss_all, 0);
76 sigaddset(&ss_caught, n);
77 DISCARD(write(sigfd, &sch, 1));
78 /* The system should reset the signal mask here. */
82 /* --- @sig_read@ --- *
84 * Arguments: @int fd@ = file descriptor to read
85 * @unsigned mode@ = thing to do with descriptor
86 * @void *p@ = uninteresting argument
90 * Use: Dispatches signals to their handlers safely.
93 static void sig_read(int fd, unsigned mode, void *p)
97 /* --- Read the currently caught signals --- *
99 * Block signals while the mask is being copied.
104 unsigned char buf[256];
106 sigprocmask(SIG_BLOCK, &ss_all, &oss);
108 sigemptyset(&ss_caught);
109 while (read(fd, buf, sizeof(buf)) > 0)
111 sigprocmask(SIG_SETMASK, &oss, 0);
114 /* --- Process the caught signals --- */
118 for (i = 0; i < nsig; i++) {
120 if (!sigismember(&ss, i))
132 /* --- @sig_add@ --- *
134 * Arguments: @sig *s@ = pointer to signal handler block
135 * @int n@ = number of the signal
136 * @void (*proc)(int n, void *p)@ = signal handler function
137 * @void *p@ = argument to pass to handler
141 * Use: Adds a signal handler.
144 void sig_add(sig *s, int n, void (*proc)(int /*n*/, void */*p*/), void *p)
146 sigstate *ss = &sigs[n];
148 /* --- Initialize the block --- */
156 /* --- Engage a signal handler, maybe --- */
160 sa.sa_handler = sig_handler;
161 sa.sa_flags = SA_NOCLDSTOP;
163 sa.sa_flags |= SA_RESTART;
165 sigemptyset(&sa.sa_mask);
166 sigaddset(&ss_all, n);
167 sigaction(n, &sa, &ss->sa);
170 /* --- Link the block into the list --- */
177 /* --- @sig_remove@ --- *
179 * Arguments: @sig *s@ = pointer to signal handler block
183 * Use: Removes the signal handler from the list.
186 void sig_remove(sig *s)
188 sigstate *ss = &sigs[s->sig];
190 /* --- Unlink the handler block --- */
193 s->next->prev = s->prev;
195 s->prev->next = s->next;
199 /* --- Maybe remove the handler --- */
202 sigaction(s->sig, &ss->sa, 0);
203 sigdelset(&ss_all, s->sig);
207 /* --- @sig_init@ --- *
209 * Arguments: @sel_state *s@ = pointer to select state
213 * Use: Initializes the signal handling system ready for use.
216 void sig_init(sel_state *s)
220 /* --- Work out how many signals there are --- */
224 unsigned min = 0, max = 0;
228 /* --- Get a good upper bound --- *
230 * Cap the search at 256. I'll be sending signal numbers as bytes.
234 while (sigaddset(&ss, nsig) == 0) {
240 /* --- Now binary search until I find the actual limit --- */
245 nsig = (min + max) >> 1;
248 if (sigaddset(&ss, nsig))
256 /* --- Initialize the signal state table --- */
261 sigs = xmalloc(nsig * sizeof(*sigs));
262 for (i = 0; i < nsig; i++)
266 /* --- Create the signal pipe --- */
269 die(1, "couldn't create pipe for signal handling");
271 /* --- Set both ends to nonblocking and close-on-exec --- */
273 fdflags(fd[0], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
274 fdflags(fd[1], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
276 /* --- Set everything up for the future --- */
279 sel_initfile(s, &sigsel, fd[0], SEL_READ, sig_read, 0);
280 sel_addfile(&sigsel);
281 sigemptyset(&ss_all);
282 sigemptyset(&ss_caught);
285 /*----- That's all, folks -------------------------------------------------*/