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