555a2a9a723f928f7e5e793616f296321fb2f14a
3 * $Id: sig.c,v 1.2 1999/08/19 18:31:04 mdw Exp $
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of the mLib utilities library.
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.
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.
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,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.2 1999/08/19 18:31:04 mdw
34 * Improve signal handling to prevent signals from being lost.
36 * Revision 1.1 1999/07/26 23:16:26 mdw
37 * Signal handling integrated into I/O system.
41 /*----- Header files ------------------------------------------------------*/
57 /*----- Data structures ---------------------------------------------------*/
59 typedef struct sigstate
{
64 /*----- Static variables --------------------------------------------------*/
66 static sel_file sigsel
;
68 static sigstate
*sigs
;
69 static sigset_t ss_all
, ss_caught
;
72 /*----- Main code ---------------------------------------------------------*/
74 /* --- @sig_handler@ --- *
76 * Arguments: @int n@ = signal number
80 * Use: Generic signal handler. Writes a single byte to the
81 * signal pipe. The byte contains the signal number. Also
82 * sets the appropriate bit in @ss_caught@ to indicate which
83 * signals are pending.
86 static void sig_handler(int n
)
89 unsigned char sch
= (unsigned char)n
;
90 sigprocmask(SIG_BLOCK
, &ss_all
, 0);
91 sigaddset(&ss_caught
, n
);
92 write(sigfd
, &sch
, 1);
93 /* The system should reset the signal mask here. */
97 /* --- @sig_read@ --- *
99 * Arguments: @int fd@ = file descriptor to read
100 * @unsigned mode@ = thing to do with descriptor
101 * @void *p@ = uninteresting argument
105 * Use: Dispatches signals to their handlers safely.
108 static void sig_read(int fd
, unsigned mode
, void *p
)
112 /* --- Read the currently caught signals --- *
114 * Block signals while the mask is being copied.
119 unsigned char buf
[256];
121 sigprocmask(SIG_BLOCK
, &ss_all
, &oss
);
123 sigemptyset(&ss_caught
);
124 while (read(fd
, buf
, sizeof(buf
)) > 0)
126 sigprocmask(SIG_SETMASK
, &oss
, 0);
129 /* --- Process the caught signals --- */
133 for (i
= 0; i
< nsig
; i
++) {
135 if (!sigismember(&ss
, i
))
147 /* --- @sig_add@ --- *
149 * Arguments: @sig *s@ = pointer to signal handler block
150 * @int n@ = number of the signal
151 * @void (*proc)(int n, void *p)@ = signal handler function
152 * @void *p@ = argument to pass to handler
156 * Use: Adds a signal handler.
159 void sig_add(sig
*s
, int n
, void (*proc
)(int /*n*/, void */
*p*/
), void *p
)
161 sigstate
*ss
= &sigs
[n
];
163 /* --- Initialize the block --- */
171 /* --- Engage a signal handler, maybe --- */
175 sa
.sa_handler
= sig_handler
;
176 sa
.sa_flags
= SA_NOCLDSTOP
;
178 sa
.sa_flags
|= SA_RESTART
;
180 sigemptyset(&sa
.sa_mask
);
181 sigaddset(&ss_all
, n
);
182 sigaction(n
, &sa
, &ss
->sa
);
185 /* --- Link the block into the list --- */
192 /* --- @sig_remove@ --- *
194 * Arguments: @sig *s@ = pointer to signal handler block
198 * Use: Removes the signal handler from the list.
201 void sig_remove(sig
*s
)
203 sigstate
*ss
= &sigs
[s
->sig
];
205 /* --- Unlink the handler block --- */
208 s
->next
->prev
= s
->prev
;
210 s
->prev
->next
= s
->next
;
214 /* --- Maybe remove the handler --- */
217 sigaction(s
->sig
, &ss
->sa
, 0);
218 sigdelset(&ss_all
, s
->sig
);
222 /* --- @sig_init@ --- *
224 * Arguments: @sel_state *s@ = pointer to select state
228 * Use: Initializes the signal handling system ready for use.
231 void sig_init(sel_state
*s
)
235 /* --- Work out how many signals there are --- */
239 unsigned min
= 0, max
= 0;
243 /* --- Get a good upper bound --- *
245 * Cap the search at 256. I'll be sending signal numbers as bytes.
249 while (sigaddset(&ss
, nsig
) == 0) {
255 /* --- Now binary search until I find the actual limit --- */
260 nsig
= (min
+ max
) >> 1;
263 if (sigaddset(&ss
, nsig
))
271 /* --- Initialize the signal state table --- */
276 sigs
= xmalloc(nsig
* sizeof(*sigs
));
277 for (i
= 0; i
< nsig
; i
++)
281 /* --- Create the signal pipe --- */
284 die(1, "couldn't create pipe for signal handling");
286 /* --- Set both ends to nonblocking and close-on-exec --- */
288 fdflags(fd
[0], O_NONBLOCK
, O_NONBLOCK
, FD_CLOEXEC
, FD_CLOEXEC
);
289 fdflags(fd
[1], O_NONBLOCK
, O_NONBLOCK
, FD_CLOEXEC
, FD_CLOEXEC
);
291 /* --- Set everything up for the future --- */
294 sel_initfile(s
, &sigsel
, fd
[0], SEL_READ
, sig_read
, 0);
295 sel_addfile(&sigsel
);
296 sigemptyset(&ss_all
);
297 sigemptyset(&ss_caught
);
300 /*----- That's all, folks -------------------------------------------------*/