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