1/* POSIX compatible signal blocking. 2 Copyright (C) 2006-2007 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 3 of the License, or 8 (at your option) 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, see <http://www.gnu.org/licenses/>. */ 17 18#include <config.h> 19 20/* Specification. */ 21#include <signal.h> 22 23#include <errno.h> 24#include <stdint.h> 25#include <stdlib.h> 26 27/* We assume that a platform without POSIX signal blocking functions also 28 does not have the POSIX sigaction() function, only the signal() function. 29 This is true for Woe32 platforms. */ 30 31/* A signal handler. */ 32typedef void (*handler_t) (int signal); 33 34int 35sigismember (const sigset_t *set, int sig) 36{ 37 if (sig >= 0 && sig < NSIG) 38 return (*set >> sig) & 1; 39 else 40 return 0; 41} 42 43int 44sigemptyset (sigset_t *set) 45{ 46 *set = 0; 47 return 0; 48} 49 50int 51sigaddset (sigset_t *set, int sig) 52{ 53 if (sig >= 0 && sig < NSIG) 54 { 55 *set |= 1U << sig; 56 return 0; 57 } 58 else 59 { 60 errno = EINVAL; 61 return -1; 62 } 63} 64 65int 66sigdelset (sigset_t *set, int sig) 67{ 68 if (sig >= 0 && sig < NSIG) 69 { 70 *set &= ~(1U << sig); 71 return 0; 72 } 73 else 74 { 75 errno = EINVAL; 76 return -1; 77 } 78} 79 80int 81sigfillset (sigset_t *set) 82{ 83 *set = (2U << (NSIG - 1)) - 1; 84 return 0; 85} 86 87/* Set of currently blocked signals. */ 88static sigset_t blocked_set /* = 0 */; 89 90/* Set of currently blocked and pending signals. */ 91static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; 92 93/* Signal handler that is installed for blocked signals. */ 94static void 95blocked_handler (int sig) 96{ 97 if (sig >= 0 && sig < NSIG) 98 pending_array[sig] = 1; 99} 100 101int 102sigpending (sigset_t *set) 103{ 104 sigset_t pending = 0; 105 int sig; 106 107 for (sig = 0; sig < NSIG; sig++) 108 if (pending_array[sig]) 109 pending |= 1U << sig; 110 return pending; 111} 112 113/* The previous signal handlers. 114 Only the array elements corresponding to blocked signals are relevant. */ 115static handler_t old_handlers[NSIG]; 116 117int 118sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) 119{ 120 if (old_set != NULL) 121 *old_set = blocked_set; 122 123 if (set != NULL) 124 { 125 sigset_t new_blocked_set; 126 sigset_t to_unblock; 127 sigset_t to_block; 128 129 switch (operation) 130 { 131 case SIG_BLOCK: 132 new_blocked_set = blocked_set | *set; 133 break; 134 case SIG_SETMASK: 135 new_blocked_set = *set; 136 break; 137 case SIG_UNBLOCK: 138 new_blocked_set = blocked_set & ~*set; 139 break; 140 default: 141 errno = EINVAL; 142 return -1; 143 } 144 to_unblock = blocked_set & ~new_blocked_set; 145 to_block = new_blocked_set & ~blocked_set; 146 147 if (to_block != 0) 148 { 149 int sig; 150 151 for (sig = 0; sig < NSIG; sig++) 152 if ((to_block >> sig) & 1) 153 { 154 pending_array[sig] = 0; 155 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) 156 blocked_set |= 1U << sig; 157 } 158 } 159 160 if (to_unblock != 0) 161 { 162 sig_atomic_t received[NSIG]; 163 int sig; 164 165 for (sig = 0; sig < NSIG; sig++) 166 if ((to_unblock >> sig) & 1) 167 { 168 if (signal (sig, old_handlers[sig]) != blocked_handler) 169 /* The application changed a signal handler while the signal 170 was blocked. We don't support this. */ 171 abort (); 172 received[sig] = pending_array[sig]; 173 blocked_set &= ~(1U << sig); 174 pending_array[sig] = 0; 175 } 176 else 177 received[sig] = 0; 178 179 for (sig = 0; sig < NSIG; sig++) 180 if (received[sig]) 181 { 182 #if HAVE_RAISE 183 raise (sig); 184 #else 185 kill (getpid (), sig); 186 #endif 187 } 188 } 189 } 190 return 0; 191} 192