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