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 else 101 if (policy != POLICY_TIMESHARE && oldmode) { 102 thread->sched_mode = TH_MODE_FIXED; 103 104 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN) 105 sched_share_decr(); 106 } 107 } 108 else { 109 if (policy == POLICY_TIMESHARE) 110 thread->saved_mode = TH_MODE_TIMESHARE; 111 else 112 thread->saved_mode = TH_MODE_FIXED; 113 } 114 115 if (priority >= thread->max_priority) 116 priority = thread->max_priority - thread->task_priority; 117 else 118 if (priority >= MINPRI_KERNEL) 119 priority -= MINPRI_KERNEL; 120 else 121 if (priority >= MINPRI_RESERVED) 122 priority -= MINPRI_RESERVED; 123 else 124 priority -= BASEPRI_DEFAULT; 125 126 priority += thread->task_priority; 127 128 if (priority > thread->max_priority) 129 priority = thread->max_priority; 130 else 131 if (priority < MINPRI) 132 priority = MINPRI; 133 134#if CONFIG_EMBEDDED 135 if ((thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) && 136 (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL)) { 137 thread->saved_importance = priority - thread->task_priority; 138 priority = MAXPRI_THROTTLE; 139 } else { 140 thread->importance = priority - thread->task_priority; 141 } 142 /* No one can have a base priority less than MAXPRI_THROTTLE */ 143 if (priority < MAXPRI_THROTTLE) 144 priority = MAXPRI_THROTTLE; 145#else /* CONFIG_EMBEDDED */ 146 thread->importance = priority - thread->task_priority; 147 148#endif /* CONFIG_EMBEDDED */ 149 150 set_priority(thread, priority); 151 } 152 153 thread_unlock(thread); 154 splx(s); 155 156 return (KERN_SUCCESS); 157} 158 159/* 160 * thread_set_policy 161 * 162 * Set scheduling policy and parameters, both base and limit, for 163 * the given thread. Policy can be any policy implemented by the 164 * processor set, whether enabled or not. 165 */ 166kern_return_t 167thread_set_policy( 168 thread_t thread, 169 processor_set_t pset, 170 policy_t policy, 171 policy_base_t base, 172 mach_msg_type_number_t base_count, 173 policy_limit_t limit, 174 mach_msg_type_number_t limit_count) 175{ 176 int max, bas; 177 kern_return_t result = KERN_SUCCESS; 178 179 if ( thread == THREAD_NULL || 180 pset == PROCESSOR_SET_NULL || pset != &pset0) 181 return (KERN_INVALID_ARGUMENT); 182 183 thread_mtx_lock(thread); 184 185 switch (policy) { 186 187 case POLICY_RR: 188 { 189 policy_rr_base_t rr_base = (policy_rr_base_t) base; 190 policy_rr_limit_t rr_limit = (policy_rr_limit_t) limit; 191 192 if ( base_count != POLICY_RR_BASE_COUNT || 193 limit_count != POLICY_RR_LIMIT_COUNT ) { 194 result = KERN_INVALID_ARGUMENT; 195 break; 196 } 197 198 bas = rr_base->base_priority; 199 max = rr_limit->max_priority; 200 if (invalid_pri(bas) || invalid_pri(max)) { 201 result = KERN_INVALID_ARGUMENT; 202 break; 203 } 204 205 break; 206 } 207 208 case POLICY_FIFO: 209 { 210 policy_fifo_base_t fifo_base = (policy_fifo_base_t) base; 211 policy_fifo_limit_t fifo_limit = (policy_fifo_limit_t) limit; 212 213 if ( base_count != POLICY_FIFO_BASE_COUNT || 214 limit_count != POLICY_FIFO_LIMIT_COUNT) { 215 result = KERN_INVALID_ARGUMENT; 216 break; 217 } 218 219 bas = fifo_base->base_priority; 220 max = fifo_limit->max_priority; 221 if (invalid_pri(bas) || invalid_pri(max)) { 222 result = KERN_INVALID_ARGUMENT; 223 break; 224 } 225 226 break; 227 } 228 229 case POLICY_TIMESHARE: 230 { 231 policy_timeshare_base_t ts_base = (policy_timeshare_base_t) base; 232 policy_timeshare_limit_t ts_limit = 233 (policy_timeshare_limit_t) limit; 234 235 if ( base_count != POLICY_TIMESHARE_BASE_COUNT || 236 limit_count != POLICY_TIMESHARE_LIMIT_COUNT ) { 237 result = KERN_INVALID_ARGUMENT; 238 break; 239 } 240 241 bas = ts_base->base_priority; 242 max = ts_limit->max_priority; 243 if (invalid_pri(bas) || invalid_pri(max)) { 244 result = KERN_INVALID_ARGUMENT; 245 break; 246 } 247 248 break; 249 } 250 251 default: 252 result = KERN_INVALID_POLICY; 253 } 254 255 if (result != KERN_SUCCESS) { 256 thread_mtx_unlock(thread); 257 258 return (result); 259 } 260 261 result = thread_policy_common(thread, policy, bas); 262 263 thread_mtx_unlock(thread); 264 265 return (result); 266} 267 268 269/* 270 * thread_policy 271 * 272 * Set scheduling policy and parameters, both base and limit, for 273 * the given thread. Policy must be a policy which is enabled for the 274 * processor set. Change contained threads if requested. 275 */ 276kern_return_t 277thread_policy( 278 thread_t thread, 279 policy_t policy, 280 policy_base_t base, 281 mach_msg_type_number_t count, 282 boolean_t set_limit) 283{ 284 kern_return_t result = KERN_SUCCESS; 285 processor_set_t pset = &pset0; 286 policy_limit_t limit = NULL; 287 int limcount = 0; 288 policy_rr_limit_data_t rr_limit; 289 policy_fifo_limit_data_t fifo_limit; 290 policy_timeshare_limit_data_t ts_limit; 291 292 if (thread == THREAD_NULL) 293 return (KERN_INVALID_ARGUMENT); 294 295 thread_mtx_lock(thread); 296 297 if ( invalid_policy(policy) || 298 ((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0 ) { 299 thread_mtx_unlock(thread); 300 301 return (KERN_INVALID_POLICY); 302 } 303 304 if (set_limit) { 305 /* 306 * Set scheduling limits to base priority. 307 */ 308 switch (policy) { 309 310 case POLICY_RR: 311 { 312 policy_rr_base_t rr_base; 313 314 if (count != POLICY_RR_BASE_COUNT) { 315 result = KERN_INVALID_ARGUMENT; 316 break; 317 } 318 319 limcount = POLICY_RR_LIMIT_COUNT; 320 rr_base = (policy_rr_base_t) base; 321 rr_limit.max_priority = rr_base->base_priority; 322 limit = (policy_limit_t) &rr_limit; 323 324 break; 325 } 326 327 case POLICY_FIFO: 328 { 329 policy_fifo_base_t fifo_base; 330 331 if (count != POLICY_FIFO_BASE_COUNT) { 332 result = KERN_INVALID_ARGUMENT; 333 break; 334 } 335 336 limcount = POLICY_FIFO_LIMIT_COUNT; 337 fifo_base = (policy_fifo_base_t) base; 338 fifo_limit.max_priority = fifo_base->base_priority; 339 limit = (policy_limit_t) &fifo_limit; 340 341 break; 342 } 343 344 case POLICY_TIMESHARE: 345 { 346 policy_timeshare_base_t ts_base; 347 348 if (count != POLICY_TIMESHARE_BASE_COUNT) { 349 result = KERN_INVALID_ARGUMENT; 350 break; 351 } 352 353 limcount = POLICY_TIMESHARE_LIMIT_COUNT; 354 ts_base = (policy_timeshare_base_t) base; 355 ts_limit.max_priority = ts_base->base_priority; 356 limit = (policy_limit_t) &ts_limit; 357 358 break; 359 } 360 361 default: 362 result = KERN_INVALID_POLICY; 363 break; 364 } 365 366 } 367 else { 368 /* 369 * Use current scheduling limits. Ensure that the 370 * new base priority will not exceed current limits. 371 */ 372 switch (policy) { 373 374 case POLICY_RR: 375 { 376 policy_rr_base_t rr_base; 377 378 if (count != POLICY_RR_BASE_COUNT) { 379 result = KERN_INVALID_ARGUMENT; 380 break; 381 } 382 383 limcount = POLICY_RR_LIMIT_COUNT; 384 rr_base = (policy_rr_base_t) base; 385 if (rr_base->base_priority > thread->max_priority) { 386 result = KERN_POLICY_LIMIT; 387 break; 388 } 389 390 rr_limit.max_priority = thread->max_priority; 391 limit = (policy_limit_t) &rr_limit; 392 393 break; 394 } 395 396 case POLICY_FIFO: 397 { 398 policy_fifo_base_t fifo_base; 399 400 if (count != POLICY_FIFO_BASE_COUNT) { 401 result = KERN_INVALID_ARGUMENT; 402 break; 403 } 404 405 limcount = POLICY_FIFO_LIMIT_COUNT; 406 fifo_base = (policy_fifo_base_t) base; 407 if (fifo_base->base_priority > thread->max_priority) { 408 result = KERN_POLICY_LIMIT; 409 break; 410 } 411 412 fifo_limit.max_priority = thread->max_priority; 413 limit = (policy_limit_t) &fifo_limit; 414 415 break; 416 } 417 418 case POLICY_TIMESHARE: 419 { 420 policy_timeshare_base_t ts_base; 421 422 if (count != POLICY_TIMESHARE_BASE_COUNT) { 423 result = KERN_INVALID_ARGUMENT; 424 break; 425 } 426 427 limcount = POLICY_TIMESHARE_LIMIT_COUNT; 428 ts_base = (policy_timeshare_base_t) base; 429 if (ts_base->base_priority > thread->max_priority) { 430 result = KERN_POLICY_LIMIT; 431 break; 432 } 433 434 ts_limit.max_priority = thread->max_priority; 435 limit = (policy_limit_t) &ts_limit; 436 437 break; 438 } 439 440 default: 441 result = KERN_INVALID_POLICY; 442 break; 443 } 444 445 } 446 447 thread_mtx_unlock(thread); 448 449 if (result == KERN_SUCCESS) 450 result = thread_set_policy(thread, pset, 451 policy, base, count, limit, limcount); 452 453 return(result); 454} 455