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 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 27 #include <sys/single_threaded.h> 28 #include <sys/types.h> 29 #include <sys/signalvar.h> 30 #include <sys/rtprio.h> 31 #include <sys/lwp.h> 32 #include <pthread.h> 33 34 #include "thr_private.h" 35 36 /*#define DEBUG_THREAD_KERN */ 37 #ifdef DEBUG_THREAD_KERN 38 #define DBG_MSG stdout_debug 39 #else 40 #define DBG_MSG(x...) 41 #endif 42 43 /* 44 * This is called when the first thread (other than the initial 45 * thread) is created. 46 * 47 * NOTE: we no longer call _thrd_rtld_fini here. 48 */ 49 int 50 _thr_setthreaded(int threaded) 51 { 52 if (((threaded == 0) ^ (__isthreaded == 0)) == 0) 53 return (0); 54 __isthreaded = threaded; 55 if (__libc_single_threaded != 0) 56 __libc_single_threaded = 0; /* sticky version */ 57 _rtld_setthreaded(threaded); 58 #if 0 59 /* save for later. */ 60 if (threaded != 0) 61 /* blah */ ; 62 else 63 /* blah */ ; 64 #endif 65 return (0); 66 } 67 68 void 69 _thr_signal_block(pthread_t curthread) 70 { 71 sigset_t set; 72 73 if (curthread->sigblock > 0) { 74 curthread->sigblock++; 75 return; 76 } 77 SIGFILLSET(set); 78 SIGDELSET(set, SIGBUS); 79 SIGDELSET(set, SIGILL); 80 SIGDELSET(set, SIGFPE); 81 SIGDELSET(set, SIGSEGV); 82 SIGDELSET(set, SIGTRAP); 83 __sys_sigprocmask(SIG_BLOCK, &set, &curthread->sigmask); 84 curthread->sigblock++; 85 } 86 87 void 88 _thr_signal_unblock(pthread_t curthread) 89 { 90 if (--curthread->sigblock == 0) 91 __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 92 } 93 94 void 95 _thr_assert_lock_level(void) 96 { 97 PANIC("locklevel <= 0"); 98 } 99 100 int 101 _thr_send_sig(pthread_t thread, int sig) 102 { 103 return (lwp_kill(-1, thread->tid, sig)); 104 } 105 106 int 107 _thr_get_tid(void) 108 { 109 return (lwp_gettid()); 110 } 111 112 /* 113 * We don't use the priority for SCHED_OTHER, but 114 * some programs may depend on getting an error when 115 * setting a priority that is out of the range returned 116 * by sched_get_priority_{min,max}. Not sure if this 117 * falls into implementation defined behavior or not. 118 */ 119 int 120 _thr_set_sched_other_prio(pthread_t pth __unused, int prio) 121 { 122 static int max, min, init_status; 123 124 /* 125 * switch (init_status) { 126 * case 0: need initialization 127 * case 1: initialization successful 128 * case 2: initialization failed. can't happen, but if 129 * it does, accept all and hope for the best. 130 * It's not like we use it anyway. 131 */ 132 if (!init_status) { 133 int tmp = errno; 134 135 errno = 0; 136 init_status = 1; 137 if (((min = sched_get_priority_min(SCHED_OTHER)) == -1) && 138 (errno != 0)) 139 init_status = 2; 140 if (((max = sched_get_priority_max(SCHED_OTHER)) == -1) && 141 (errno != 0)) 142 init_status = 2; 143 errno = tmp; 144 } 145 if ((init_status == 2) || ((prio >= min) && (prio <= max))) { 146 return 0; 147 } 148 errno = ENOTSUP; 149 return -1; 150 } 151 152 int 153 _rtp_to_schedparam(const struct rtprio *rtp, int *policy, 154 struct sched_param *param) 155 { 156 switch(rtp->type) { 157 case RTP_PRIO_REALTIME: 158 *policy = SCHED_RR; 159 param->sched_priority = RTP_PRIO_MAX - rtp->prio; 160 break; 161 case RTP_PRIO_FIFO: 162 *policy = SCHED_FIFO; 163 param->sched_priority = RTP_PRIO_MAX - rtp->prio; 164 break; 165 default: 166 *policy = SCHED_OTHER; 167 param->sched_priority = 0; 168 break; 169 } 170 return (0); 171 } 172 173 int 174 _schedparam_to_rtp(int policy, const struct sched_param *param, 175 struct rtprio *rtp) 176 { 177 switch(policy) { 178 case SCHED_RR: 179 rtp->type = RTP_PRIO_REALTIME; 180 rtp->prio = RTP_PRIO_MAX - param->sched_priority; 181 break; 182 case SCHED_FIFO: 183 rtp->type = RTP_PRIO_FIFO; 184 rtp->prio = RTP_PRIO_MAX - param->sched_priority; 185 break; 186 case SCHED_OTHER: 187 default: 188 rtp->type = RTP_PRIO_NORMAL; 189 rtp->prio = 0; 190 break; 191 } 192 return (0); 193 } 194 195 int 196 _thr_getscheduler(lwpid_t lwpid, int *policy, struct sched_param *param) 197 { 198 pthread_t curthread = tls_get_curthread(); 199 struct rtprio rtp; 200 int ret; 201 202 if (lwpid == curthread->tid) 203 lwpid = -1; 204 ret = lwp_rtprio(RTP_LOOKUP, 0, lwpid, &rtp); 205 if (ret == -1) 206 return (ret); 207 _rtp_to_schedparam(&rtp, policy, param); 208 return (0); 209 } 210 211 int 212 _thr_setscheduler(lwpid_t lwpid, int policy, const struct sched_param *param) 213 { 214 pthread_t curthread = tls_get_curthread(); 215 struct rtprio rtp; 216 217 if (lwpid == curthread->tid) 218 lwpid = -1; 219 _schedparam_to_rtp(policy, param, &rtp); 220 return (lwp_rtprio(RTP_SET, 0, lwpid, &rtp)); 221 } 222