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.5 2006/06/05 07:26:10 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 /* 48 * Called from very low level boot code, i386/i386/machdep.c/init386(). 49 * We cannot do anything fancy. no malloc's, no nothing other then 50 * static initialization. 51 */ 52 struct usched * 53 usched_init(void) 54 { 55 const char *defsched; 56 57 defsched = getenv("kern.user_scheduler"); 58 59 /* 60 * Add various userland schedulers to the system. 61 */ 62 usched_ctl(&usched_bsd4, USCH_ADD); 63 usched_ctl(&usched_dummy, USCH_ADD); 64 if (defsched == NULL ) 65 return(&usched_bsd4); 66 if (strcmp(defsched, "bsd4") == 0) 67 return(&usched_bsd4); 68 printf("WARNING: Running dummy userland scheduler\n"); 69 return(&usched_dummy); 70 } 71 72 /* 73 * USCHED_CTL 74 * 75 * SYNOPSIS: 76 * Add/remove usched to/from list. 77 * 78 * ARGUMENTS: 79 * usched - pointer to target scheduler 80 * action - addition or removal ? 81 * 82 * RETURN VALUES: 83 * 0 - success 84 * EINVAL - error 85 */ 86 int 87 usched_ctl(struct usched *usched, int action) 88 { 89 struct usched *item; /* temporaly for TAILQ processing */ 90 int error = 0; 91 92 switch(action) { 93 case USCH_ADD: 94 /* 95 * Make sure it isn't already on the list 96 */ 97 #ifdef INVARIANTS 98 TAILQ_FOREACH(item, &usched_list, entry) { 99 KKASSERT(item != usched); 100 } 101 #endif 102 /* 103 * Optional callback to the scheduler before we officially 104 * add it to the list. 105 */ 106 if (usched->usched_register) 107 usched->usched_register(); 108 TAILQ_INSERT_TAIL(&usched_list, usched, entry); 109 break; 110 case USCH_REM: 111 /* 112 * Do not allow the default scheduler to be removed 113 */ 114 if (strcmp(usched->name, "bsd4") == 0) { 115 error = EINVAL; 116 break; 117 } 118 TAILQ_FOREACH(item, &usched_list, entry) { 119 if (item == usched) 120 break; 121 } 122 if (item) { 123 if (item->usched_unregister) 124 item->usched_unregister(); 125 TAILQ_REMOVE(&usched_list, item, entry); 126 } else { 127 error = EINVAL; 128 } 129 break; 130 default: 131 error = EINVAL; 132 break; 133 } 134 return (error); 135 } 136 137 /* 138 * USCHED_SET(syscall) 139 * 140 * SYNOPSIS: 141 * Setting up a proc's usched. 142 * 143 * ARGUMENTS: 144 * pid - 145 * cmd - 146 * data - 147 * bytes - 148 * RETURN VALUES: 149 * 0 - success 150 * EINVAL - error 151 */ 152 int 153 sys_usched_set(struct usched_set_args *uap) 154 { 155 struct proc *p = curthread->td_proc; 156 struct usched *item; /* temporaly for TAILQ processing */ 157 int error; 158 char buffer[NAME_LENGTH]; 159 cpumask_t mask; 160 struct lwp *lp; 161 int cpuid; 162 163 if ((error = suser(curthread)) != 0) 164 return (error); 165 166 if (uap->pid != 0 && uap->pid != curthread->td_proc->p_pid) 167 return (EINVAL); 168 169 lp = curthread->td_lwp; 170 switch (uap->cmd) { 171 case USCHED_SET_SCHEDULER: 172 if ((error = copyinstr(uap->data, buffer, sizeof(buffer), 173 NULL)) != 0) 174 return (error); 175 TAILQ_FOREACH(item, &usched_list, entry) { 176 if ((strcmp(item->name, buffer) == 0)) 177 break; 178 } 179 180 /* 181 * If the scheduler for a process is being changed, disassociate 182 * the old scheduler before switching to the new one. 183 * 184 * XXX we might have to add an additional ABI call to do a 'full 185 * disassociation' and another ABI call to do a 'full 186 * reassociation' 187 */ 188 if (item && item != p->p_usched) { 189 p->p_usched->release_curproc(&p->p_lwp); 190 p->p_usched = item; 191 } else if (item == NULL) { 192 error = EINVAL; 193 } 194 break; 195 case USCHED_SET_CPU: 196 if (uap->bytes != sizeof(int)) 197 return (EINVAL); 198 error = copyin(uap->data, &cpuid, sizeof(int)); 199 if (error) 200 break; 201 if ((smp_active_mask & (1 << cpuid)) == 0) { 202 error = EINVAL; 203 break; 204 } 205 lp->lwp_cpumask = 1 << cpuid; 206 if (cpuid != mycpu->gd_cpuid) 207 lwkt_migratecpu(cpuid); 208 break; 209 case USCHED_ADD_CPU: 210 if (uap->bytes != sizeof(int)) 211 return (EINVAL); 212 error = copyin(uap->data, &cpuid, sizeof(int)); 213 if (error) 214 break; 215 if (!(smp_active_mask & (1 << cpuid))) { 216 error = EINVAL; 217 break; 218 } 219 lp->lwp_cpumask |= 1 << cpuid; 220 break; 221 case USCHED_DEL_CPU: 222 if (uap->bytes != sizeof(int)) 223 return (EINVAL); 224 error = copyin(uap->data, &cpuid, sizeof(int)); 225 if (error) 226 break; 227 lp = curthread->td_lwp; 228 mask = lp->lwp_cpumask & smp_active_mask & ~(1 << cpuid); 229 if (mask == 0) 230 error = EPERM; 231 else { 232 lp->lwp_cpumask &= ~(1 << cpuid); 233 if ((lp->lwp_cpumask & mycpu->gd_cpumask) == 0) { 234 cpuid = bsfl(lp->lwp_cpumask & smp_active_mask); 235 lwkt_migratecpu(cpuid); 236 } 237 } 238 default: 239 error = EINVAL; 240 break; 241 } 242 return (error); 243 } 244 245