njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Signal-related libc stuff. m_libcsignal.c ---*/ |
| 4 | /*--------------------------------------------------------------------*/ |
| 5 | |
| 6 | /* |
| 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
| 9 | |
sewardj | 9ebd6e0 | 2007-01-08 06:01:59 +0000 | [diff] [blame] | 10 | Copyright (C) 2000-2007 Julian Seward |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 11 | jseward@acm.org |
| 12 | |
| 13 | This program is free software; you can redistribute it and/or |
| 14 | modify it under the terms of the GNU General Public License as |
| 15 | published by the Free Software Foundation; either version 2 of the |
| 16 | License, or (at your option) any later version. |
| 17 | |
| 18 | This program is distributed in the hope that it will be useful, but |
| 19 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 21 | General Public License for more details. |
| 22 | |
| 23 | You should have received a copy of the GNU General Public License |
| 24 | along with this program; if not, write to the Free Software |
| 25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 26 | 02111-1307, USA. |
| 27 | |
| 28 | The GNU General Public License is contained in the file COPYING. |
| 29 | */ |
| 30 | |
njn | c7561b9 | 2005-06-19 01:24:32 +0000 | [diff] [blame] | 31 | #include "pub_core_basics.h" |
sewardj | 1383bdd | 2006-10-17 01:30:47 +0000 | [diff] [blame] | 32 | #include "pub_core_debuglog.h" |
sewardj | 4cfea4f | 2006-10-14 19:26:10 +0000 | [diff] [blame] | 33 | #include "pub_core_vki.h" |
sewardj | 1383bdd | 2006-10-17 01:30:47 +0000 | [diff] [blame] | 34 | #include "pub_core_vkiscnums.h" |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 35 | #include "pub_core_libcbase.h" |
| 36 | #include "pub_core_libcassert.h" |
njn | 9abd608 | 2005-06-17 21:31:45 +0000 | [diff] [blame] | 37 | #include "pub_core_syscall.h" |
sewardj | 1383bdd | 2006-10-17 01:30:47 +0000 | [diff] [blame] | 38 | #include "pub_core_libcsignal.h" /* self */ |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 39 | |
| 40 | /* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on |
| 41 | success and -1 on error. */ |
sewardj | 1383bdd | 2006-10-17 01:30:47 +0000 | [diff] [blame] | 42 | /* I believe the indexing scheme in ->sig[] is also correct for |
| 43 | 32- and 64-bit AIX (verified 27 July 06). */ |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 44 | |
| 45 | Int VG_(sigfillset)( vki_sigset_t* set ) |
| 46 | { |
| 47 | Int i; |
| 48 | if (set == NULL) |
| 49 | return -1; |
| 50 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 51 | set->sig[i] = ~(UWord)0x0; |
| 52 | return 0; |
| 53 | } |
| 54 | |
| 55 | Int VG_(sigemptyset)( vki_sigset_t* set ) |
| 56 | { |
| 57 | Int i; |
| 58 | if (set == NULL) |
| 59 | return -1; |
| 60 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 61 | set->sig[i] = 0x0; |
| 62 | return 0; |
| 63 | } |
| 64 | |
| 65 | Bool VG_(isemptysigset)( const vki_sigset_t* set ) |
| 66 | { |
| 67 | Int i; |
| 68 | vg_assert(set != NULL); |
| 69 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 70 | if (set->sig[i] != 0x0) return False; |
| 71 | return True; |
| 72 | } |
| 73 | |
| 74 | Bool VG_(isfullsigset)( const vki_sigset_t* set ) |
| 75 | { |
| 76 | Int i; |
| 77 | vg_assert(set != NULL); |
| 78 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 79 | if (set->sig[i] != ~(UWord)0x0) return False; |
| 80 | return True; |
| 81 | } |
| 82 | |
| 83 | Bool VG_(iseqsigset)( const vki_sigset_t* set1, const vki_sigset_t* set2 ) |
| 84 | { |
| 85 | Int i; |
| 86 | vg_assert(set1 != NULL && set2 != NULL); |
| 87 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 88 | if (set1->sig[i] != set2->sig[i]) return False; |
| 89 | return True; |
| 90 | } |
| 91 | |
| 92 | |
| 93 | Int VG_(sigaddset)( vki_sigset_t* set, Int signum ) |
| 94 | { |
| 95 | if (set == NULL) |
| 96 | return -1; |
| 97 | if (signum < 1 || signum > _VKI_NSIG) |
| 98 | return -1; |
| 99 | signum--; |
| 100 | set->sig[signum / _VKI_NSIG_BPW] |= (1UL << (signum % _VKI_NSIG_BPW)); |
| 101 | return 0; |
| 102 | } |
| 103 | |
| 104 | Int VG_(sigdelset)( vki_sigset_t* set, Int signum ) |
| 105 | { |
| 106 | if (set == NULL) |
| 107 | return -1; |
| 108 | if (signum < 1 || signum > _VKI_NSIG) |
| 109 | return -1; |
| 110 | signum--; |
| 111 | set->sig[signum / _VKI_NSIG_BPW] &= ~(1UL << (signum % _VKI_NSIG_BPW)); |
| 112 | return 0; |
| 113 | } |
| 114 | |
| 115 | Int VG_(sigismember) ( const vki_sigset_t* set, Int signum ) |
| 116 | { |
| 117 | if (set == NULL) |
| 118 | return 0; |
| 119 | if (signum < 1 || signum > _VKI_NSIG) |
| 120 | return 0; |
| 121 | signum--; |
| 122 | if (1 & ((set->sig[signum / _VKI_NSIG_BPW]) >> (signum % _VKI_NSIG_BPW))) |
| 123 | return 1; |
| 124 | else |
| 125 | return 0; |
| 126 | } |
| 127 | |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 128 | /* Add all signals in src to dst. */ |
| 129 | void VG_(sigaddset_from_set)( vki_sigset_t* dst, vki_sigset_t* src ) |
| 130 | { |
| 131 | Int i; |
| 132 | vg_assert(dst != NULL && src != NULL); |
| 133 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 134 | dst->sig[i] |= src->sig[i]; |
| 135 | } |
| 136 | |
| 137 | /* Remove all signals in src from dst. */ |
| 138 | void VG_(sigdelset_from_set)( vki_sigset_t* dst, vki_sigset_t* src ) |
| 139 | { |
| 140 | Int i; |
| 141 | vg_assert(dst != NULL && src != NULL); |
| 142 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 143 | dst->sig[i] &= ~(src->sig[i]); |
| 144 | } |
| 145 | |
| 146 | |
| 147 | /* The functions sigaction, sigprocmask, sigpending and sigsuspend |
| 148 | return 0 on success and -1 on error. |
| 149 | */ |
| 150 | Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset) |
| 151 | { |
| 152 | SysRes res = VG_(do_syscall4)(__NR_rt_sigprocmask, |
| 153 | how, (UWord)set, (UWord)oldset, |
| 154 | _VKI_NSIG_WORDS * sizeof(UWord)); |
| 155 | return res.isError ? -1 : 0; |
| 156 | } |
| 157 | |
| 158 | |
| 159 | Int VG_(sigaction) ( Int signum, const struct vki_sigaction* act, |
| 160 | struct vki_sigaction* oldact) |
| 161 | { |
| 162 | SysRes res = VG_(do_syscall4)(__NR_rt_sigaction, |
| 163 | signum, (UWord)act, (UWord)oldact, |
| 164 | _VKI_NSIG_WORDS * sizeof(UWord)); |
| 165 | return res.isError ? -1 : 0; |
| 166 | } |
| 167 | |
| 168 | |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 169 | Int VG_(kill)( Int pid, Int signo ) |
| 170 | { |
| 171 | SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo); |
| 172 | return res.isError ? -1 : 0; |
| 173 | } |
| 174 | |
| 175 | |
| 176 | Int VG_(tkill)( ThreadId tid, Int signo ) |
| 177 | { |
| 178 | SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS); |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 179 | res = VG_(do_syscall2)(__NR_tkill, tid, signo); |
sewardj | 1383bdd | 2006-10-17 01:30:47 +0000 | [diff] [blame] | 180 | if (res.isError && res.err == VKI_ENOSYS) |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 181 | res = VG_(do_syscall2)(__NR_kill, tid, signo); |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 182 | return res.isError ? -1 : 0; |
| 183 | } |
| 184 | |
sewardj | 1383bdd | 2006-10-17 01:30:47 +0000 | [diff] [blame] | 185 | |
| 186 | /* A cut-down version of POSIX sigtimedwait: poll for pending signals |
| 187 | mentioned in the sigset_t, and if any are present, select one |
| 188 | arbitrarily, return its number (which must be > 0), and put |
| 189 | auxiliary info about it in the siginfo_t, and make it |
| 190 | not-pending-any-more. If none are pending, return zero. The _zero |
| 191 | refers to the fact that there is zero timeout, so if no signals are |
| 192 | pending it returns immediately. Perhaps a better name would be |
| 193 | 'sigpoll'. Returns -1 on error, 0 if no signals pending, and n > 0 |
| 194 | if signal n was selected. |
| 195 | |
| 196 | The Linux implementation is trivial: do the corresponding syscall. |
| 197 | |
| 198 | The AIX implementation is horrible and probably broken in a dozen |
| 199 | obscure ways. I suspect it's only thread-safe because V forces |
| 200 | single-threadedness. */ |
| 201 | |
| 202 | #if defined(VGO_linux) |
| 203 | Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, |
| 204 | vki_siginfo_t *info ) |
| 205 | { |
| 206 | static const struct vki_timespec zero = { 0, 0 }; |
| 207 | SysRes res = VG_(do_syscall4)(__NR_rt_sigtimedwait, (UWord)set, (UWord)info, |
| 208 | (UWord)&zero, sizeof(*set)); |
| 209 | return res.isError ? -1 : res.res; |
| 210 | } |
| 211 | |
| 212 | #elif defined(VGO_aix5) |
| 213 | /* The general idea is: |
| 214 | - use sigpending to find out which signals are pending |
| 215 | - choose one |
| 216 | - temporarily set its handler to sigtimedwait_zero_handler |
| 217 | - use sigsuspend atomically unblock it and wait for the signal. |
| 218 | Upon return, sigsuspend restores the signal mask to what it |
| 219 | was to start with. |
| 220 | - Restore the handler for the signal to whatever it was before. |
| 221 | */ |
| 222 | |
| 223 | /* A signal handler which does nothing (it doesn't need to). It does |
| 224 | however check that it's not handing a sync signal for which |
| 225 | returning is meaningless. */ |
| 226 | static void sigtimedwait_zero_handler ( Int sig ) |
| 227 | { |
| 228 | vg_assert(sig != VKI_SIGILL); |
| 229 | vg_assert(sig != VKI_SIGSEGV); |
| 230 | vg_assert(sig != VKI_SIGBUS); |
| 231 | vg_assert(sig != VKI_SIGTRAP); |
| 232 | /* do nothing */ |
| 233 | } |
| 234 | |
| 235 | Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, |
| 236 | vki_siginfo_t *info ) |
| 237 | { |
| 238 | Int i, ir; |
| 239 | SysRes sr; |
| 240 | vki_sigset_t pending, blocked, allbutone; |
| 241 | struct vki_sigaction sa, saved_sa; |
| 242 | |
| 243 | /* Find out what's pending: AIX _sigpending */ |
| 244 | sr = VG_(do_syscall1)(__NR__sigpending, (UWord)&pending); |
| 245 | vg_assert(!sr.isError); |
| 246 | |
| 247 | /* don't try for signals not in 'set' */ |
| 248 | /* pending = pending `intersect` set */ |
| 249 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 250 | pending.sig[i] &= set->sig[i]; |
| 251 | |
| 252 | /* don't try for signals not blocked at the moment */ |
| 253 | ir = VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &blocked); |
| 254 | vg_assert(ir == 0); |
| 255 | |
| 256 | /* pending = pending `intersect` blocked */ |
| 257 | for (i = 0; i < _VKI_NSIG_WORDS; i++) |
| 258 | pending.sig[i] &= blocked.sig[i]; |
| 259 | |
| 260 | /* decide which signal we're going to snarf */ |
| 261 | for (i = 1; i < _VKI_NSIG; i++) |
| 262 | if (VG_(sigismember)(&pending,i)) |
| 263 | break; |
| 264 | |
| 265 | if (i == _VKI_NSIG) |
| 266 | return 0; |
| 267 | |
| 268 | /* fetch signal i. |
| 269 | pre: i is blocked and pending |
| 270 | pre: we are the only thread running |
| 271 | */ |
| 272 | /* Set up alternative signal handler */ |
| 273 | VG_(sigfillset)(&allbutone); |
| 274 | VG_(sigdelset)(&allbutone, i); |
| 275 | sa.sa_mask = allbutone; |
| 276 | sa.ksa_handler = &sigtimedwait_zero_handler; |
| 277 | sa.sa_flags = 0; |
| 278 | ir = VG_(sigaction)(i, &sa, &saved_sa); |
| 279 | vg_assert(ir == 0); |
| 280 | |
| 281 | /* Switch signal masks and wait for the signal. This should happen |
| 282 | immediately, since we've already established it is pending and |
| 283 | blocked. */ |
| 284 | sr = VG_(do_syscall1)(__NR__sigsuspend, (UWord)&allbutone); |
| 285 | vg_assert(sr.isError); |
| 286 | if (0) |
| 287 | VG_(debugLog)(0, "libcsignal", |
| 288 | "sigtimedwait_zero: sigsuspend got res %ld err %ld\n", |
| 289 | sr.res, sr.err); |
| 290 | vg_assert(sr.res == (UWord)-1); |
| 291 | |
| 292 | /* Restore signal's handler to whatever it was before */ |
| 293 | ir = VG_(sigaction)(i, &saved_sa, NULL); |
| 294 | vg_assert(ir == 0); |
| 295 | |
| 296 | /* This is bogus - we could get more info from the sighandler. */ |
| 297 | VG_(memset)( info, 0, sizeof(*info) ); |
| 298 | info->si_signo = i; |
| 299 | |
| 300 | return i; |
| 301 | } |
| 302 | |
| 303 | #else |
| 304 | # error Unknown OS |
| 305 | #endif |
| 306 | |
njn | de62cbf | 2005-06-10 22:08:14 +0000 | [diff] [blame] | 307 | /*--------------------------------------------------------------------*/ |
| 308 | /*--- end ---*/ |
| 309 | /*--------------------------------------------------------------------*/ |