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