1 /* 2 * Copyright (c) 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Sergey Glushchenko <deen@smz.com.ua> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/kern/kern_usched.c,v 1.9 2007/07/02 17:06:55 dillon Exp $ 35 */ 36 37 #include <sys/errno.h> 38 #include <sys/globaldata.h> /* curthread */ 39 #include <sys/proc.h> 40 #include <sys/sysproto.h> /* struct usched_set_args */ 41 #include <sys/systm.h> /* strcmp() */ 42 #include <sys/usched.h> 43 #include <machine/smp.h> 44 45 static TAILQ_HEAD(, usched) usched_list = TAILQ_HEAD_INITIALIZER(usched_list); 46 47 cpumask_t usched_mastermask = -1; 48 49 /* 50 * Called from very low level boot code, i386/i386/machdep.c/init386(). 51 * We cannot do anything fancy. no malloc's, no nothing other then 52 * static initialization. 53 */ 54 struct usched * 55 usched_init(void) 56 { 57 const char *defsched; 58 59 defsched = kgetenv("kern.user_scheduler"); 60 61 /* 62 * Add various userland schedulers to the system. 63 */ 64 usched_ctl(&usched_bsd4, USCH_ADD); 65 usched_ctl(&usched_dummy, USCH_ADD); 66 if (defsched == NULL ) 67 return(&usched_bsd4); 68 if (strcmp(defsched, "bsd4") == 0) 69 return(&usched_bsd4); 70 kprintf("WARNING: Running dummy userland scheduler\n"); 71 return(&usched_dummy); 72 } 73 74 /* 75 * USCHED_CTL 76 * 77 * SYNOPSIS: 78 * Add/remove usched to/from list. 79 * 80 * ARGUMENTS: 81 * usched - pointer to target scheduler 82 * action - addition or removal ? 83 * 84 * RETURN VALUES: 85 * 0 - success 86 * EINVAL - error 87 */ 88 int 89 usched_ctl(struct usched *usched, int action) 90 { 91 struct usched *item; /* temporaly for TAILQ processing */ 92 int error = 0; 93 94 switch(action) { 95 case USCH_ADD: 96 /* 97 * Make sure it isn't already on the list 98 */ 99 #ifdef INVARIANTS 100 TAILQ_FOREACH(item, &usched_list, entry) { 101 KKASSERT(item != usched); 102 } 103 #endif 104 /* 105 * Optional callback to the scheduler before we officially 106 * add it to the list. 107 */ 108 if (usched->usched_register) 109 usched->usched_register(); 110 TAILQ_INSERT_TAIL(&usched_list, usched, entry); 111 break; 112 case USCH_REM: 113 /* 114 * Do not allow the default scheduler to be removed 115 */ 116 if (strcmp(usched->name, "bsd4") == 0) { 117 error = EINVAL; 118 break; 119 } 120 TAILQ_FOREACH(item, &usched_list, entry) { 121 if (item == usched) 122 break; 123 } 124 if (item) { 125 if (item->usched_unregister) 126 item->usched_unregister(); 127 TAILQ_REMOVE(&usched_list, item, entry); 128 } else { 129 error = EINVAL; 130 } 131 break; 132 default: 133 error = EINVAL; 134 break; 135 } 136 return (error); 137 } 138 139 /* 140 * USCHED_SET(syscall) 141 * 142 * SYNOPSIS: 143 * Setting up a proc's usched. 144 * 145 * ARGUMENTS: 146 * pid - 147 * cmd - 148 * data - 149 * bytes - 150 * RETURN VALUES: 151 * 0 - success 152 * EINVAL - error 153 */ 154 int 155 sys_usched_set(struct usched_set_args *uap) 156 { 157 struct proc *p = curthread->td_proc; 158 struct usched *item; /* temporaly for TAILQ processing */ 159 int error; 160 char buffer[NAME_LENGTH]; 161 cpumask_t mask; 162 struct lwp *lp; 163 int cpuid; 164 165 if ((error = suser(curthread)) != 0) 166 return (error); 167 168 if (uap->pid != 0 && uap->pid != curthread->td_proc->p_pid) 169 return (EINVAL); 170 171 lp = curthread->td_lwp; 172 switch (uap->cmd) { 173 case USCHED_SET_SCHEDULER: 174 if ((error = copyinstr(uap->data, buffer, sizeof(buffer), 175 NULL)) != 0) 176 return (error); 177 TAILQ_FOREACH(item, &usched_list, entry) { 178 if ((strcmp(item->name, buffer) == 0)) 179 break; 180 } 181 182 /* 183 * If the scheduler for a process is being changed, disassociate 184 * the old scheduler before switching to the new one. 185 * 186 * XXX we might have to add an additional ABI call to do a 'full 187 * disassociation' and another ABI call to do a 'full 188 * reassociation' 189 */ 190 /* XXX lwp have to deal with multiple lwps here */ 191 if (p->p_nthreads != 1) 192 return (EINVAL); 193 if (item && item != p->p_usched) { 194 /* XXX lwp */ 195 p->p_usched->release_curproc(ONLY_LWP_IN_PROC(p)); 196 p->p_usched = item; 197 } else if (item == NULL) { 198 error = EINVAL; 199 } 200 break; 201 case USCHED_SET_CPU: 202 if (uap->bytes != sizeof(int)) 203 return (EINVAL); 204 error = copyin(uap->data, &cpuid, sizeof(int)); 205 if (error) 206 break; 207 if (cpuid < 0 || cpuid >= ncpus) { 208 error = EFBIG; 209 break; 210 } 211 if ((smp_active_mask & (1 << cpuid)) == 0) { 212 error = EINVAL; 213 break; 214 } 215 lp->lwp_cpumask = 1 << cpuid; 216 if (cpuid != mycpu->gd_cpuid) 217 lwkt_migratecpu(cpuid); 218 break; 219 case USCHED_ADD_CPU: 220 if (uap->bytes != sizeof(int)) 221 return (EINVAL); 222 error = copyin(uap->data, &cpuid, sizeof(int)); 223 if (error) 224 break; 225 if (cpuid < 0 || cpuid >= ncpus) { 226 error = EFBIG; 227 break; 228 } 229 if (!(smp_active_mask & (1 << cpuid))) { 230 error = EINVAL; 231 break; 232 } 233 lp->lwp_cpumask |= 1 << cpuid; 234 break; 235 case USCHED_DEL_CPU: 236 if (uap->bytes != sizeof(int)) 237 return (EINVAL); 238 error = copyin(uap->data, &cpuid, sizeof(int)); 239 if (error) 240 break; 241 if (cpuid < 0 || cpuid >= ncpus) { 242 error = EFBIG; 243 break; 244 } 245 lp = curthread->td_lwp; 246 mask = lp->lwp_cpumask & smp_active_mask & ~(1 << cpuid); 247 if (mask == 0) 248 error = EPERM; 249 else { 250 lp->lwp_cpumask &= ~(1 << cpuid); 251 if ((lp->lwp_cpumask & mycpu->gd_cpumask) == 0) { 252 cpuid = bsfl(lp->lwp_cpumask & smp_active_mask); 253 lwkt_migratecpu(cpuid); 254 } 255 } 256 default: 257 error = EINVAL; 258 break; 259 } 260 return (error); 261 } 262 263