1 /* 2 * Copyright (c) 2003 Jeffrey Roberson <jeff@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 unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/types.h> 31 #include <sys/signalvar.h> 32 #include <sys/time.h> 33 #include <sys/timespec.h> 34 #include <pthread.h> 35 #include <signal.h> 36 #include <stdlib.h> 37 #include <errno.h> 38 #include <unistd.h> 39 40 #include "thr_private.h" 41 42 /* XXX Why can't I get this from time.h? :-( */ 43 #define timespecsub(vvp, uvp) \ 44 do { \ 45 (vvp)->tv_sec -= (uvp)->tv_sec; \ 46 (vvp)->tv_nsec -= (uvp)->tv_nsec; \ 47 if ((vvp)->tv_nsec < 0) { \ 48 (vvp)->tv_sec--; \ 49 (vvp)->tv_nsec += 1000000000; \ 50 } \ 51 } while (0) 52 53 void 54 _thread_critical_enter(pthread_t pthread) 55 { 56 _thread_sigblock(); 57 UMTX_LOCK(&pthread->lock); 58 } 59 60 void 61 _thread_critical_exit(pthread_t pthread) 62 { 63 UMTX_UNLOCK(&pthread->lock); 64 _thread_sigunblock(); 65 } 66 67 void 68 _thread_sigblock() 69 { 70 sigset_t set; 71 sigset_t sav; 72 73 /* 74 * Block all signals. 75 */ 76 SIGFILLSET(set); 77 SIGADDSET(set, SIGTHR); 78 #ifdef _PTHREADS_INVARIANTS 79 SIGDELSET(set, SIGABRT); 80 #endif 81 SIGDELSET(set, SIGTRAP); 82 83 /* If we have already blocked signals, just up the refcount */ 84 if (++curthread->signest > 1) 85 return; 86 PTHREAD_ASSERT(curthread->signest == 1, 87 ("Blocked signal nesting level must be 1!")); 88 89 if (__sys_sigprocmask(SIG_SETMASK, &set, &sav)) { 90 _thread_printf(STDERR_FILENO, "Critical Enter: sig err %d\n", 91 errno); 92 abort(); 93 } 94 curthread->savedsig = sav; 95 } 96 97 void 98 _thread_sigunblock() 99 { 100 sigset_t set; 101 102 /* We might be in a nested 'blocked signal' section */ 103 if (--curthread->signest > 0) 104 return; 105 PTHREAD_ASSERT(curthread->signest == 0, 106 ("Non-Zero blocked signal nesting level.")); 107 108 /* 109 * Restore signals. 110 */ 111 set = curthread->savedsig; 112 if (__sys_sigprocmask(SIG_SETMASK, &set, NULL)) { 113 _thread_printf(STDERR_FILENO, "Critical Exit: sig err %d\n", 114 errno); 115 abort(); 116 } 117 } 118 119 int 120 _thread_suspend(pthread_t pthread, const struct timespec *abstime) 121 { 122 struct timespec remaining; 123 struct timespec *ts; 124 siginfo_t info; 125 int error; 126 127 /* 128 * Compute the remainder of the run time. 129 */ 130 if (abstime) { 131 struct timespec now; 132 struct timeval tv; 133 134 GET_CURRENT_TOD(tv); 135 TIMEVAL_TO_TIMESPEC(&tv, &now); 136 137 remaining = *abstime; 138 timespecsub(&remaining, &now); 139 ts = &remaining; 140 } else 141 ts = NULL; 142 143 error = sigtimedwait(&_thread_suspend_sigset, &info, ts); 144 error = (error == -1) ? errno : 0; 145 return (error); 146 } 147