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. */ 33 typedef void (*handler_t) (int signal); 34 35 int 36 sigismember (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 44 int 45 sigemptyset (sigset_t *set) 46 { 47 *set = 0; 48 return 0; 49 } 50 51 int 52 sigaddset (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 66 int 67 sigdelset (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 81 int 82 sigfillset (sigset_t *set) 83 { 84 *set = (2U << (NSIG - 1)) - 1; 85 return 0; 86 } 87 88 /* Set of currently blocked signals. */ 89 static sigset_t blocked_set /* = 0 */; 90 91 /* Set of currently blocked and pending signals. */ 92 static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; 93 94 /* Signal handler that is installed for blocked signals. */ 95 static void 96 blocked_handler (int sig) 97 { 98 if (sig >= 0 && sig < NSIG) 99 pending_array[sig] = 1; 100 } 101 102 int 103 sigpending (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. */ 116 static handler_t old_handlers[NSIG]; 117 118 int 119 sigprocmask (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 } 193