source: trunk/essentials/sys-devel/m4/lib/sigprocmask.c

Last change on this file was 3090, checked in by bird, 18 years ago

m4 1.4.8

File size: 4.0 KB
Line 
1/* POSIX compatible signal blocking.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19#include <config.h>
20
21/* Specification. */
22#include "sigprocmask.h"
23
24#include <errno.h>
25#include <stdint.h>
26#include <stdlib.h>
27
28/* We assume that a platform without POSIX signal blocking functions also
29 does not have the POSIX sigaction() function, only the signal() function.
30 This is true for Woe32 platforms. */
31
32/* A signal handler. */
33typedef void (*handler_t) (int signal);
34
35int
36sigismember (const sigset_t *set, int sig)
37{
38 if (sig >= 0 && sig < NSIG)
39 return (*set >> sig) & 1;
40 else
41 return 0;
42}
43
44int
45sigemptyset (sigset_t *set)
46{
47 *set = 0;
48 return 0;
49}
50
51int
52sigaddset (sigset_t *set, int sig)
53{
54 if (sig >= 0 && sig < NSIG)
55 {
56 *set |= 1U << sig;
57 return 0;
58 }
59 else
60 {
61 errno = EINVAL;
62 return -1;
63 }
64}
65
66int
67sigdelset (sigset_t *set, int sig)
68{
69 if (sig >= 0 && sig < NSIG)
70 {
71 *set &= ~(1U << sig);
72 return 0;
73 }
74 else
75 {
76 errno = EINVAL;
77 return -1;
78 }
79}
80
81int
82sigfillset (sigset_t *set)
83{
84 *set = (2U << (NSIG - 1)) - 1;
85 return 0;
86}
87
88/* Set of currently blocked signals. */
89static sigset_t blocked_set /* = 0 */;
90
91/* Set of currently blocked and pending signals. */
92static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
93
94/* Signal handler that is installed for blocked signals. */
95static void
96blocked_handler (int sig)
97{
98 if (sig >= 0 && sig < NSIG)
99 pending_array[sig] = 1;
100}
101
102int
103sigpending (sigset_t *set)
104{
105 sigset_t pending = 0;
106 int sig;
107
108 for (sig = 0; sig < NSIG; sig++)
109 if (pending_array[sig])
110 pending |= 1U << sig;
111 return pending;
112}
113
114/* The previous signal handlers.
115 Only the array elements corresponding to blocked signals are relevant. */
116static handler_t old_handlers[NSIG];
117
118int
119sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
120{
121 if (old_set != NULL)
122 *old_set = blocked_set;
123
124 if (set != NULL)
125 {
126 sigset_t new_blocked_set;
127 sigset_t to_unblock;
128 sigset_t to_block;
129
130 switch (operation)
131 {
132 case SIG_BLOCK:
133 new_blocked_set = blocked_set | *set;
134 break;
135 case SIG_SETMASK:
136 new_blocked_set = *set;
137 break;
138 case SIG_UNBLOCK:
139 new_blocked_set = blocked_set & ~*set;
140 break;
141 default:
142 errno = EINVAL;
143 return -1;
144 }
145 to_unblock = blocked_set & ~new_blocked_set;
146 to_block = new_blocked_set & ~blocked_set;
147
148 if (to_block != 0)
149 {
150 int sig;
151
152 for (sig = 0; sig < NSIG; sig++)
153 if ((to_block >> sig) & 1)
154 {
155 pending_array[sig] = 0;
156 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
157 blocked_set |= 1U << sig;
158 }
159 }
160
161 if (to_unblock != 0)
162 {
163 sig_atomic_t received[NSIG];
164 int sig;
165
166 for (sig = 0; sig < NSIG; sig++)
167 if ((to_unblock >> sig) & 1)
168 {
169 if (signal (sig, old_handlers[sig]) != blocked_handler)
170 /* The application changed a signal handler while the signal
171 was blocked. We don't support this. */
172 abort ();
173 received[sig] = pending_array[sig];
174 blocked_set &= ~(1U << sig);
175 pending_array[sig] = 0;
176 }
177 else
178 received[sig] = 0;
179
180 for (sig = 0; sig < NSIG; sig++)
181 if (received[sig])
182 {
183 #if HAVE_RAISE
184 raise (sig);
185 #else
186 kill (getpid (), sig);
187 #endif
188 }
189 }
190 }
191 return 0;
192}
Note: See TracBrowser for help on using the repository browser.