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 SIGDELSET(set, SIGTRAP); 78 79 /* If we have already blocked signals, just up the refcount */ 80 if (++curthread->signest > 1) 81 return; 82 PTHREAD_ASSERT(curthread->signest == 1, 83 ("Blocked signal nesting level must be 1!")); 84 85 if (__sys_sigprocmask(SIG_SETMASK, &set, &sav)) { 86 _thread_printf(STDERR_FILENO, "Critical Enter: sig err %d\n", 87 errno); 88 abort(); 89 } 90 curthread->savedsig = sav; 91 } 92 93 void 94 _thread_sigunblock() 95 { 96 sigset_t set; 97 98 /* We might be in a nested 'blocked signal' section */ 99 if (--curthread->signest > 0) 100 return; 101 PTHREAD_ASSERT(curthread->signest == 0, 102 ("Non-Zero blocked signal nesting level.")); 103 104 /* 105 * Restore signals. 106 */ 107 set = curthread->savedsig; 108 if (__sys_sigprocmask(SIG_SETMASK, &set, NULL)) { 109 _thread_printf(STDERR_FILENO, "Critical Exit: sig err %d\n", 110 errno); 111 abort(); 112 } 113 } 114 115 int 116 _thread_suspend(pthread_t pthread, const struct timespec *abstime) 117 { 118 struct timespec remaining; 119 struct timespec *ts; 120 int error; 121 122 /* 123 * Compute the remainder of the run time. 124 */ 125 if (abstime) { 126 struct timespec now; 127 struct timeval tv; 128 129 GET_CURRENT_TOD(tv); 130 TIMEVAL_TO_TIMESPEC(&tv, &now); 131 132 remaining = *abstime; 133 timespecsub(&remaining, &now); 134 ts = &remaining; 135 136 /* 137 * NOTE: timespecsub() makes sure the tv_nsec member >= 0. 138 */ 139 if (ts->tv_sec < 0) 140 return (ETIMEDOUT); 141 } else 142 ts = NULL; 143 error = thr_suspend(ts); 144 return (error == -1 ? errno : error); 145 } 146