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 static sigset_t restore; 54 55 void 56 _thread_critical_enter(pthread_t pthread) 57 { 58 _thread_sigblock(); 59 UMTX_LOCK(&pthread->lock); 60 } 61 62 void 63 _thread_critical_exit(pthread_t pthread) 64 { 65 UMTX_UNLOCK(&pthread->lock); 66 _thread_sigunblock(); 67 } 68 69 void 70 _thread_sigblock() 71 { 72 sigset_t set; 73 sigset_t sav; 74 75 /* 76 * Block all signals. 77 */ 78 SIGFILLSET(set); 79 SIGADDSET(set, SIGTHR); 80 #ifdef _PTHREADS_INVARIANTS 81 SIGDELSET(set, SIGABRT); 82 #endif 83 84 /* If we have already blocked signals, just up the refcount */ 85 if (++curthread->signest > 1) 86 return; 87 PTHREAD_ASSERT(curthread->signest == 1, 88 ("Blocked signal nesting level must be 1!")); 89 90 if (__sys_sigprocmask(SIG_SETMASK, &set, &sav)) { 91 _thread_printf(STDERR_FILENO, "Critical Enter: sig err %d\n", 92 errno); 93 abort(); 94 } 95 curthread->savedsig = sav; 96 } 97 98 void 99 _thread_sigunblock() 100 { 101 sigset_t set; 102 103 /* We might be in a nested 'blocked signal' section */ 104 if (--curthread->signest > 0) 105 return; 106 PTHREAD_ASSERT(curthread->signest == 0, 107 ("Non-Zero blocked signal nesting level.")); 108 109 /* 110 * Restore signals. 111 */ 112 set = curthread->savedsig; 113 if (__sys_sigprocmask(SIG_SETMASK, &set, NULL)) { 114 _thread_printf(STDERR_FILENO, "Critical Exit: sig err %d\n", 115 errno); 116 abort(); 117 } 118 } 119 120 void 121 GIANT_LOCK(pthread_t pthread) 122 { 123 sigset_t set; 124 sigset_t sav; 125 int error; 126 127 /* 128 * Block all signals. 129 */ 130 SIGFILLSET(set); 131 132 /* 133 * We can not use the global 'restore' set until after we have 134 * acquired the giant lock. 135 */ 136 #if 0 137 error = __sys_sigprocmask(SIG_SETMASK, &set, &sav); 138 if (error) { 139 _thread_printf(STDERR_FILENO, "GIANT_LOCK: sig err %d\n", 140 errno); 141 abort(); 142 } 143 #endif 144 145 error = umtx_lock(&_giant_mutex, pthread->thr_id); 146 if (error) { 147 _thread_printf(STDERR_FILENO, "GIANT_LOCK: %d\n", errno); 148 abort(); 149 } 150 151 restore = sav; 152 } 153 154 void 155 GIANT_UNLOCK(pthread_t pthread) 156 { 157 sigset_t set; 158 int error; 159 160 /* 161 * restore is protected by giant. We could restore our signal state 162 * incorrectly if someone else set restore between unlocking giant 163 * and restoring the signal mask. To avoid this we cache a copy prior 164 * to the unlock. 165 */ 166 set = restore; 167 168 error = umtx_unlock(&_giant_mutex, pthread->thr_id); 169 if (error) { 170 _thread_printf(STDERR_FILENO, "GIANT_UNLOCK: %d\n", errno); 171 abort(); 172 } 173 174 #if 0 175 /* 176 * Restore signals. 177 */ 178 error = __sys_sigprocmask(SIG_SETMASK, &set, NULL); 179 if (error) { 180 _thread_printf(STDERR_FILENO, "GIANT_UNLOCK: sig err %d\n", 181 errno); 182 abort(); 183 } 184 #endif 185 } 186 187 int 188 _thread_suspend(pthread_t pthread, struct timespec *abstime) 189 { 190 struct timespec remaining; 191 struct timespec *ts; 192 siginfo_t info; 193 int error; 194 195 /* 196 * Compute the remainder of the run time. 197 */ 198 if (abstime) { 199 struct timespec now; 200 struct timeval tv; 201 202 GET_CURRENT_TOD(tv); 203 TIMEVAL_TO_TIMESPEC(&tv, &now); 204 205 remaining = *abstime; 206 timespecsub(&remaining, &now); 207 ts = &remaining; 208 } else 209 ts = NULL; 210 211 error = sigtimedwait(&_thread_suspend_sigset, &info, ts); 212 error = (error == -1) ? errno : 0; 213 return (error); 214 } 215