1/* 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 * 31 */ 32 33/* The routines in this module are all obsolete */ 34 35#include <mach/boolean.h> 36#include <mach/thread_switch.h> 37#include <ipc/ipc_port.h> 38#include <ipc/ipc_space.h> 39#include <kern/ipc_kobject.h> 40#include <kern/processor.h> 41#include <kern/sched.h> 42#include <kern/sched_prim.h> 43#include <kern/spl.h> 44#include <kern/task.h> 45#include <kern/thread.h> 46#include <mach/policy.h> 47 48#include <kern/syscall_subr.h> 49#include <mach/mach_host_server.h> 50#include <mach/mach_syscalls.h> 51 52#include <kern/misc_protos.h> 53#include <kern/spl.h> 54#include <kern/sched.h> 55#include <kern/sched_prim.h> 56#include <kern/assert.h> 57#include <kern/thread.h> 58#include <mach/mach_host_server.h> 59#include <mach/thread_act_server.h> 60#include <mach/host_priv_server.h> 61 62/* 63 * thread_policy_common: 64 * 65 * Set scheduling policy & priority for thread. 66 */ 67static kern_return_t 68thread_policy_common( 69 thread_t thread, 70 integer_t policy, 71 integer_t priority) 72{ 73 spl_t s; 74 75 if ( thread == THREAD_NULL || 76 invalid_policy(policy) ) 77 return(KERN_INVALID_ARGUMENT); 78 79 if (thread->static_param) 80 return (KERN_SUCCESS); 81 82 if ((policy == POLICY_TIMESHARE) 83 && !SCHED(supports_timeshare_mode)()) 84 policy = TH_MODE_FIXED; 85 86 s = splsched(); 87 thread_lock(thread); 88 89 if ( (thread->sched_mode != TH_MODE_REALTIME) && 90 (thread->saved_mode != TH_MODE_REALTIME) ) { 91 if (!(thread->sched_flags & TH_SFLAG_DEMOTED_MASK)) { 92 boolean_t oldmode = thread->sched_mode == TH_MODE_TIMESHARE; 93 94 if (policy == POLICY_TIMESHARE && !oldmode) { 95 thread->sched_mode = TH_MODE_TIMESHARE; 96 97 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN) { 98 sched_share_incr(); 99 100 if (thread->max_priority <= MAXPRI_THROTTLE) 101 sched_background_incr(); 102 } 103 } 104 else 105 if (policy != POLICY_TIMESHARE && oldmode) { 106 thread->sched_mode = TH_MODE_FIXED; 107 108 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN) { 109 if (thread->max_priority <= MAXPRI_THROTTLE) 110 sched_background_decr(); 111 112 sched_share_decr(); 113 } 114 } 115 } 116 else { 117 if (policy == POLICY_TIMESHARE) 118 thread->saved_mode = TH_MODE_TIMESHARE; 119 else 120 thread->saved_mode = TH_MODE_FIXED; 121 } 122 123 if (priority >= thread->max_priority) 124 priority = thread->max_priority - thread->task_priority; 125 else 126 if (priority >= MINPRI_KERNEL) 127 priority -= MINPRI_KERNEL; 128 else 129 if (priority >= MINPRI_RESERVED) 130 priority -= MINPRI_RESERVED; 131 else 132 priority -= BASEPRI_DEFAULT; 133 134 priority += thread->task_priority; 135 136 if (priority > thread->max_priority) 137 priority = thread->max_priority; 138 else 139 if (priority < MINPRI) 140 priority = MINPRI; 141 142 thread->importance = priority - thread->task_priority; 143 144 145 set_priority(thread, priority); 146 } 147 148 thread_unlock(thread); 149 splx(s); 150 151 return (KERN_SUCCESS); 152} 153 154/* 155 * thread_set_policy 156 * 157 * Set scheduling policy and parameters, both base and limit, for 158 * the given thread. Policy can be any policy implemented by the 159 * processor set, whether enabled or not. 160 */ 161kern_return_t 162thread_set_policy( 163 thread_t thread, 164 processor_set_t pset, 165 policy_t policy, 166 policy_base_t base, 167 mach_msg_type_number_t base_count, 168 policy_limit_t limit, 169 mach_msg_type_number_t limit_count) 170{ 171 int max, bas; 172 kern_return_t result = KERN_SUCCESS; 173 174 if ( thread == THREAD_NULL || 175 pset == PROCESSOR_SET_NULL || pset != &pset0) 176 return (KERN_INVALID_ARGUMENT); 177 178 thread_mtx_lock(thread); 179 180 switch (policy) { 181 182 case POLICY_RR: 183 { 184 policy_rr_base_t rr_base = (policy_rr_base_t) base; 185 policy_rr_limit_t rr_limit = (policy_rr_limit_t) limit; 186 187 if ( base_count != POLICY_RR_BASE_COUNT || 188 limit_count != POLICY_RR_LIMIT_COUNT ) { 189 result = KERN_INVALID_ARGUMENT; 190 break; 191 } 192 193 bas = rr_base->base_priority; 194 max = rr_limit->max_priority; 195 if (invalid_pri(bas) || invalid_pri(max)) { 196 result = KERN_INVALID_ARGUMENT; 197 break; 198 } 199 200 break; 201 } 202 203 case POLICY_FIFO: 204 { 205 policy_fifo_base_t fifo_base = (policy_fifo_base_t) base; 206 policy_fifo_limit_t fifo_limit = (policy_fifo_limit_t) limit; 207 208 if ( base_count != POLICY_FIFO_BASE_COUNT || 209 limit_count != POLICY_FIFO_LIMIT_COUNT) { 210 result = KERN_INVALID_ARGUMENT; 211 break; 212 } 213 214 bas = fifo_base->base_priority; 215 max = fifo_limit->max_priority; 216 if (invalid_pri(bas) || invalid_pri(max)) { 217 result = KERN_INVALID_ARGUMENT; 218 break; 219 } 220 221 break; 222 } 223 224 case POLICY_TIMESHARE: 225 { 226 policy_timeshare_base_t ts_base = (policy_timeshare_base_t) base; 227 policy_timeshare_limit_t ts_limit = 228 (policy_timeshare_limit_t) limit; 229 230 if ( base_count != POLICY_TIMESHARE_BASE_COUNT || 231 limit_count != POLICY_TIMESHARE_LIMIT_COUNT ) { 232 result = KERN_INVALID_ARGUMENT; 233 break; 234 } 235 236 bas = ts_base->base_priority; 237 max = ts_limit->max_priority; 238 if (invalid_pri(bas) || invalid_pri(max)) { 239 result = KERN_INVALID_ARGUMENT; 240 break; 241 } 242 243 break; 244 } 245 246 default: 247 result = KERN_INVALID_POLICY; 248 } 249 250 if (result != KERN_SUCCESS) { 251 thread_mtx_unlock(thread); 252 253 return (result); 254 } 255 256 result = thread_policy_common(thread, policy, bas); 257 258 thread_mtx_unlock(thread); 259 260 return (result); 261} 262 263 264/* 265 * thread_policy 266 * 267 * Set scheduling policy and parameters, both base and limit, for 268 * the given thread. Policy must be a policy which is enabled for the 269 * processor set. Change contained threads if requested. 270 */ 271kern_return_t 272thread_policy( 273 thread_t thread, 274 policy_t policy, 275 policy_base_t base, 276 mach_msg_type_number_t count, 277 boolean_t set_limit) 278{ 279 kern_return_t result = KERN_SUCCESS; 280 processor_set_t pset = &pset0; 281 policy_limit_t limit = NULL; 282 int limcount = 0; 283 policy_rr_limit_data_t rr_limit; 284 policy_fifo_limit_data_t fifo_limit; 285 policy_timeshare_limit_data_t ts_limit; 286 287 if (thread == THREAD_NULL) 288 return (KERN_INVALID_ARGUMENT); 289 290 thread_mtx_lock(thread); 291 292 if ( invalid_policy(policy) || 293 ((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0 ) { 294 thread_mtx_unlock(thread); 295 296 return (KERN_INVALID_POLICY); 297 } 298 299 if (set_limit) { 300 /* 301 * Set scheduling limits to base priority. 302 */ 303 switch (policy) { 304 305 case POLICY_RR: 306 { 307 policy_rr_base_t rr_base; 308 309 if (count != POLICY_RR_BASE_COUNT) { 310 result = KERN_INVALID_ARGUMENT; 311 break; 312 } 313 314 limcount = POLICY_RR_LIMIT_COUNT; 315 rr_base = (policy_rr_base_t) base; 316 rr_limit.max_priority = rr_base->base_priority; 317 limit = (policy_limit_t) &rr_limit; 318 319 break; 320 } 321 322 case POLICY_FIFO: 323 { 324 policy_fifo_base_t fifo_base; 325 326 if (count != POLICY_FIFO_BASE_COUNT) { 327 result = KERN_INVALID_ARGUMENT; 328 break; 329 } 330 331 limcount = POLICY_FIFO_LIMIT_COUNT; 332 fifo_base = (policy_fifo_base_t) base; 333 fifo_limit.max_priority = fifo_base->base_priority; 334 limit = (policy_limit_t) &fifo_limit; 335 336 break; 337 } 338 339 case POLICY_TIMESHARE: 340 { 341 policy_timeshare_base_t ts_base; 342 343 if (count != POLICY_TIMESHARE_BASE_COUNT) { 344 result = KERN_INVALID_ARGUMENT; 345 break; 346 } 347 348 limcount = POLICY_TIMESHARE_LIMIT_COUNT; 349 ts_base = (policy_timeshare_base_t) base; 350 ts_limit.max_priority = ts_base->base_priority; 351 limit = (policy_limit_t) &ts_limit; 352 353 break; 354 } 355 356 default: 357 result = KERN_INVALID_POLICY; 358 break; 359 } 360 361 } 362 else { 363 /* 364 * Use current scheduling limits. Ensure that the 365 * new base priority will not exceed current limits. 366 */ 367 switch (policy) { 368 369 case POLICY_RR: 370 { 371 policy_rr_base_t rr_base; 372 373 if (count != POLICY_RR_BASE_COUNT) { 374 result = KERN_INVALID_ARGUMENT; 375 break; 376 } 377 378 limcount = POLICY_RR_LIMIT_COUNT; 379 rr_base = (policy_rr_base_t) base; 380 if (rr_base->base_priority > thread->max_priority) { 381 result = KERN_POLICY_LIMIT; 382 break; 383 } 384 385 rr_limit.max_priority = thread->max_priority; 386 limit = (policy_limit_t) &rr_limit; 387 388 break; 389 } 390 391 case POLICY_FIFO: 392 { 393 policy_fifo_base_t fifo_base; 394 395 if (count != POLICY_FIFO_BASE_COUNT) { 396 result = KERN_INVALID_ARGUMENT; 397 break; 398 } 399 400 limcount = POLICY_FIFO_LIMIT_COUNT; 401 fifo_base = (policy_fifo_base_t) base; 402 if (fifo_base->base_priority > thread->max_priority) { 403 result = KERN_POLICY_LIMIT; 404 break; 405 } 406 407 fifo_limit.max_priority = thread->max_priority; 408 limit = (policy_limit_t) &fifo_limit; 409 410 break; 411 } 412 413 case POLICY_TIMESHARE: 414 { 415 policy_timeshare_base_t ts_base; 416 417 if (count != POLICY_TIMESHARE_BASE_COUNT) { 418 result = KERN_INVALID_ARGUMENT; 419 break; 420 } 421 422 limcount = POLICY_TIMESHARE_LIMIT_COUNT; 423 ts_base = (policy_timeshare_base_t) base; 424 if (ts_base->base_priority > thread->max_priority) { 425 result = KERN_POLICY_LIMIT; 426 break; 427 } 428 429 ts_limit.max_priority = thread->max_priority; 430 limit = (policy_limit_t) &ts_limit; 431 432 break; 433 } 434 435 default: 436 result = KERN_INVALID_POLICY; 437 break; 438 } 439 440 } 441 442 thread_mtx_unlock(thread); 443 444 if (result == KERN_SUCCESS) 445 result = thread_set_policy(thread, pset, 446 policy, base, count, limit, limcount); 447 448 return(result); 449} 450