1 /* 2 * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27 #include "namespace.h" 28 #include <sys/signalvar.h> 29 #include <machine/tls.h> 30 #include <signal.h> 31 #include <errno.h> 32 #include <string.h> 33 #include <pthread.h> 34 #include "un-namespace.h" 35 36 #include "thr_private.h" 37 38 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2) 39 #include <sys/file.h> 40 #include <stdio.h> 41 #include <string.h> 42 #endif 43 44 /* #define DEBUG_SIGNAL */ 45 #ifdef DEBUG_SIGNAL 46 #define DBG_MSG stdout_debug 47 #else 48 #define DBG_MSG(x...) 49 #endif 50 51 int __sigwait(const sigset_t *set, int *sig); 52 int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 53 int __sigtimedwait(const sigset_t *set, siginfo_t *info, 54 const struct timespec * timeout); 55 56 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2) 57 static void _thr_debug_sig(int signo); 58 #endif 59 60 static void 61 sigcancel_handler(int sig __unused, siginfo_t *info __unused, 62 ucontext_t *ucp __unused) 63 { 64 struct pthread *curthread = tls_get_curthread(); 65 66 if (curthread->cancelflags & THR_CANCEL_AT_POINT) 67 _pthread_testcancel(); 68 _thr_ast(curthread); 69 } 70 71 void 72 _thr_ast(struct pthread *curthread) 73 { 74 if (!THR_IN_CRITICAL(curthread)) { 75 if (__predict_false((curthread->flags & 76 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 77 == THR_FLAGS_NEED_SUSPEND)) 78 _thr_suspend_check(curthread); 79 } 80 } 81 82 void 83 _thr_suspend_check(struct pthread *curthread) 84 { 85 umtx_t cycle; 86 87 /* 88 * Blocks SIGCANCEL which other threads must send. 89 */ 90 _thr_signal_block(curthread); 91 92 /* 93 * Increase critical_count, here we don't use THR_LOCK/UNLOCK 94 * because we are leaf code, we don't want to recursively call 95 * ourself. 96 */ 97 curthread->critical_count++; 98 THR_UMTX_LOCK(curthread, &(curthread)->lock); 99 while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 100 THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 101 curthread->cycle++; 102 cycle = curthread->cycle; 103 104 /* Wake the thread suspending us. */ 105 _thr_umtx_wake(&curthread->cycle, 0); 106 107 /* 108 * if we are from pthread_exit, we don't want to 109 * suspend, just go and die. 110 */ 111 if (curthread->state == PS_DEAD) 112 break; 113 curthread->flags |= THR_FLAGS_SUSPENDED; 114 THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 115 _thr_umtx_wait(&curthread->cycle, cycle, NULL, 0); 116 THR_UMTX_LOCK(curthread, &(curthread)->lock); 117 curthread->flags &= ~THR_FLAGS_SUSPENDED; 118 } 119 THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 120 curthread->critical_count--; 121 122 _thr_signal_unblock(curthread); 123 } 124 125 void 126 _thr_signal_init(void) 127 { 128 struct sigaction act; 129 130 /* Install cancel handler. */ 131 SIGEMPTYSET(act.sa_mask); 132 act.sa_flags = SA_SIGINFO | SA_RESTART; 133 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 134 __sys_sigaction(SIGCANCEL, &act, NULL); 135 136 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2) 137 /* 138 * If enabled, rwlock, mutex, and condition variable operations 139 * are recorded in a text buffer and signal 63 dumps the buffer 140 * to /tmp/cond${pid}.log. 141 */ 142 act.sa_flags = SA_RESTART; 143 act.sa_handler = _thr_debug_sig; 144 __sys_sigaction(63, &act, NULL); 145 #endif 146 } 147 148 void 149 _thr_signal_deinit(void) 150 { 151 } 152 153 int 154 _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 155 { 156 /* Check if the signal number is out of range: */ 157 if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 158 /* Return an invalid argument: */ 159 errno = EINVAL; 160 return (-1); 161 } 162 163 return __sys_sigaction(sig, act, oact); 164 } 165 166 __strong_reference(_sigaction, sigaction); 167 168 int 169 _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 170 { 171 const sigset_t *p = set; 172 sigset_t newset; 173 174 if (how != SIG_UNBLOCK) { 175 if (set != NULL) { 176 newset = *set; 177 SIGDELSET(newset, SIGCANCEL); 178 p = &newset; 179 } 180 } 181 return (__sys_sigprocmask(how, p, oset)); 182 } 183 184 __strong_reference(_sigprocmask, sigprocmask); 185 186 int 187 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 188 { 189 if (_sigprocmask(how, set, oset)) 190 return (errno); 191 return (0); 192 } 193 194 __strong_reference(_pthread_sigmask, pthread_sigmask); 195 196 int 197 _sigsuspend(const sigset_t * set) 198 { 199 struct pthread *curthread = tls_get_curthread(); 200 sigset_t newset; 201 const sigset_t *pset; 202 int oldcancel; 203 int ret; 204 205 if (SIGISMEMBER(*set, SIGCANCEL)) { 206 newset = *set; 207 SIGDELSET(newset, SIGCANCEL); 208 pset = &newset; 209 } else 210 pset = set; 211 212 oldcancel = _thr_cancel_enter(curthread); 213 ret = __sys_sigsuspend(pset); 214 _thr_cancel_leave(curthread, oldcancel); 215 216 return (ret); 217 } 218 219 __strong_reference(_sigsuspend, sigsuspend); 220 221 int 222 __sigtimedwait(const sigset_t *set, siginfo_t *info, 223 const struct timespec * timeout) 224 { 225 struct pthread *curthread = tls_get_curthread(); 226 sigset_t newset; 227 const sigset_t *pset; 228 int oldcancel; 229 int ret; 230 231 if (SIGISMEMBER(*set, SIGCANCEL)) { 232 newset = *set; 233 SIGDELSET(newset, SIGCANCEL); 234 pset = &newset; 235 } else 236 pset = set; 237 oldcancel = _thr_cancel_enter(curthread); 238 ret = __sys_sigtimedwait(pset, info, timeout); 239 _thr_cancel_leave(curthread, oldcancel); 240 return (ret); 241 } 242 243 __strong_reference(__sigtimedwait, sigtimedwait); 244 245 int 246 __sigwaitinfo(const sigset_t *set, siginfo_t *info) 247 { 248 struct pthread *curthread = tls_get_curthread(); 249 sigset_t newset; 250 const sigset_t *pset; 251 int oldcancel; 252 int ret; 253 254 if (SIGISMEMBER(*set, SIGCANCEL)) { 255 newset = *set; 256 SIGDELSET(newset, SIGCANCEL); 257 pset = &newset; 258 } else 259 pset = set; 260 261 oldcancel = _thr_cancel_enter(curthread); 262 ret = __sys_sigwaitinfo(pset, info); 263 _thr_cancel_leave(curthread, oldcancel); 264 return (ret); 265 } 266 267 __strong_reference(__sigwaitinfo, sigwaitinfo); 268 269 int 270 __sigwait(const sigset_t *set, int *sig) 271 { 272 int s; 273 274 s = __sigwaitinfo(set, NULL); 275 if (s > 0) { 276 *sig = s; 277 return (0); 278 } 279 return (errno); 280 } 281 282 __strong_reference(__sigwait, sigwait); 283 284 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2) 285 286 #define LOGBUF_SIZE (4 * 1024 * 1024) 287 #define LOGBUF_MASK (LOGBUF_SIZE - 1) 288 289 char LogBuf[LOGBUF_SIZE]; 290 unsigned long LogWIndex; 291 292 void 293 _thr_log(const char *buf, size_t bytes) 294 { 295 struct pthread *curthread; 296 unsigned long i; 297 char prefix[32]; 298 size_t plen; 299 300 curthread = tls_get_curthread(); 301 if (curthread) { 302 plen = snprintf(prefix, sizeof(prefix), "%d.%d: ", 303 (int)__sys_getpid(), 304 curthread->tid); 305 } else { 306 plen = snprintf(prefix, sizeof(prefix), "unknown: "); 307 } 308 309 if (bytes == 0) 310 bytes = strlen(buf); 311 i = atomic_fetchadd_long(&LogWIndex, plen + bytes); 312 i = i & LOGBUF_MASK; 313 if (plen <= (size_t)(LOGBUF_SIZE - i)) { 314 bcopy(prefix, LogBuf + i, plen); 315 } else { 316 bcopy(prefix, LogBuf + i, LOGBUF_SIZE - i); 317 plen -= LOGBUF_SIZE - i; 318 bcopy(prefix, LogBuf, plen); 319 } 320 321 i += plen; 322 i = i & LOGBUF_MASK; 323 if (bytes <= (size_t)(LOGBUF_SIZE - i)) { 324 bcopy(buf, LogBuf + i, bytes); 325 } else { 326 bcopy(buf, LogBuf + i, LOGBUF_SIZE - i); 327 bytes -= LOGBUF_SIZE - i; 328 bcopy(buf, LogBuf, bytes); 329 } 330 } 331 332 static void 333 _thr_debug_sig(int signo __unused) 334 { 335 char buf[256]; 336 int fd; 337 unsigned long i; 338 339 snprintf(buf, sizeof(buf), "/tmp/cond%d.log", (int)__sys_getpid()); 340 fd = open(buf, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666); 341 if (fd >= 0) { 342 i = LogWIndex; 343 if (i < LOGBUF_SIZE) { 344 write(fd, LogBuf, i); 345 } else { 346 i &= LOGBUF_MASK; 347 write(fd, LogBuf + i, LOGBUF_SIZE - i); 348 write(fd, LogBuf, i); 349 } 350 close(fd); 351 } 352 } 353 354 #endif 355