]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/thread_policy.c
xnu-2050.9.2.tar.gz
[apple/xnu.git] / osfmk / kern / thread_policy.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b 28
91447636
A
29#include <mach/mach_types.h>
30#include <mach/thread_act_server.h>
31
32#include <kern/kern_types.h>
55e303ae 33#include <kern/processor.h>
1c79356b 34#include <kern/thread.h>
2d21ac55 35#include <kern/affinity.h>
1c79356b 36
0b4e3aa0
A
37static void
38thread_recompute_priority(
39 thread_t thread);
40
6d2010ae
A
41#if CONFIG_EMBEDDED
42static void
43thread_throttle(
44 thread_t thread,
45 integer_t task_priority);
46
47extern int mach_do_background_thread(thread_t thread, int prio);
48#endif
b0d623f7
A
49
50
1c79356b
A
51kern_return_t
52thread_policy_set(
91447636 53 thread_t thread,
1c79356b
A
54 thread_policy_flavor_t flavor,
55 thread_policy_t policy_info,
56 mach_msg_type_number_t count)
57{
1c79356b 58
91447636 59 if (thread == THREAD_NULL)
1c79356b
A
60 return (KERN_INVALID_ARGUMENT);
61
b0d623f7
A
62 if (thread->static_param)
63 return (KERN_SUCCESS);
64
65 return (thread_policy_set_internal(thread, flavor, policy_info, count));
66}
67
68kern_return_t
69thread_policy_set_internal(
70 thread_t thread,
71 thread_policy_flavor_t flavor,
72 thread_policy_t policy_info,
73 mach_msg_type_number_t count)
74{
75 kern_return_t result = KERN_SUCCESS;
76 spl_t s;
77
91447636
A
78 thread_mtx_lock(thread);
79 if (!thread->active) {
80 thread_mtx_unlock(thread);
1c79356b
A
81
82 return (KERN_TERMINATED);
83 }
1c79356b
A
84 switch (flavor) {
85
0b4e3aa0 86 case THREAD_EXTENDED_POLICY:
1c79356b 87 {
0b4e3aa0
A
88 boolean_t timeshare = TRUE;
89
90 if (count >= THREAD_EXTENDED_POLICY_COUNT) {
91 thread_extended_policy_t info;
92
93 info = (thread_extended_policy_t)policy_info;
94 timeshare = info->timeshare;
95 }
1c79356b 96
6d2010ae
A
97 if (!SCHED(supports_timeshare_mode)())
98 timeshare = FALSE;
99
1c79356b
A
100 s = splsched();
101 thread_lock(thread);
102
6d2010ae
A
103 if (!(thread->sched_flags & TH_SFLAG_DEMOTED_MASK)) {
104 integer_t oldmode = (thread->sched_mode == TH_MODE_TIMESHARE);
55e303ae 105
6d2010ae
A
106 if (timeshare) {
107 thread->sched_mode = TH_MODE_TIMESHARE;
1c79356b 108
6d2010ae
A
109 if (!oldmode) {
110 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
111 sched_share_incr();
112 }
55e303ae 113 }
6d2010ae
A
114 else {
115 thread->sched_mode = TH_MODE_FIXED;
1c79356b 116
6d2010ae
A
117 if (oldmode) {
118 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
119 sched_share_decr();
120 }
55e303ae
A
121 }
122
0b4e3aa0
A
123 thread_recompute_priority(thread);
124 }
125 else {
1c79356b 126
0b4e3aa0 127 if (timeshare)
6d2010ae 128 thread->saved_mode = TH_MODE_TIMESHARE;
0b4e3aa0 129 else
6d2010ae 130 thread->saved_mode = TH_MODE_FIXED;
0b4e3aa0 131 }
1c79356b
A
132
133 thread_unlock(thread);
134 splx(s);
135
136 break;
137 }
138
139 case THREAD_TIME_CONSTRAINT_POLICY:
140 {
141 thread_time_constraint_policy_t info;
142
143 if (count < THREAD_TIME_CONSTRAINT_POLICY_COUNT) {
144 result = KERN_INVALID_ARGUMENT;
145 break;
146 }
147
148 info = (thread_time_constraint_policy_t)policy_info;
55e303ae
A
149 if ( info->constraint < info->computation ||
150 info->computation > max_rt_quantum ||
0b4e3aa0
A
151 info->computation < min_rt_quantum ) {
152 result = KERN_INVALID_ARGUMENT;
153 break;
154 }
1c79356b
A
155
156 s = splsched();
157 thread_lock(thread);
158
1c79356b
A
159 thread->realtime.period = info->period;
160 thread->realtime.computation = info->computation;
161 thread->realtime.constraint = info->constraint;
162 thread->realtime.preemptible = info->preemptible;
163
6d2010ae
A
164 if (thread->sched_flags & TH_SFLAG_DEMOTED_MASK) {
165 thread->saved_mode = TH_MODE_REALTIME;
166 }
6d2010ae
A
167 else {
168 if (thread->sched_mode == TH_MODE_TIMESHARE) {
2d21ac55
A
169 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
170 sched_share_decr();
55e303ae 171 }
6d2010ae 172 thread->sched_mode = TH_MODE_REALTIME;
0b4e3aa0
A
173 thread_recompute_priority(thread);
174 }
1c79356b
A
175
176 thread_unlock(thread);
177 splx(s);
178
179 break;
180 }
181
182 case THREAD_PRECEDENCE_POLICY:
183 {
184 thread_precedence_policy_t info;
185
186 if (count < THREAD_PRECEDENCE_POLICY_COUNT) {
187 result = KERN_INVALID_ARGUMENT;
188 break;
189 }
1c79356b
A
190 info = (thread_precedence_policy_t)policy_info;
191
192 s = splsched();
193 thread_lock(thread);
194
195 thread->importance = info->importance;
196
0b4e3aa0 197 thread_recompute_priority(thread);
1c79356b
A
198
199 thread_unlock(thread);
200 splx(s);
201
202 break;
203 }
204
2d21ac55
A
205 case THREAD_AFFINITY_POLICY:
206 {
207 thread_affinity_policy_t info;
208
209 if (!thread_affinity_is_supported()) {
210 result = KERN_NOT_SUPPORTED;
211 break;
212 }
213 if (count < THREAD_AFFINITY_POLICY_COUNT) {
214 result = KERN_INVALID_ARGUMENT;
215 break;
216 }
217
218 info = (thread_affinity_policy_t) policy_info;
219 /*
220 * Unlock the thread mutex here and
221 * return directly after calling thread_affinity_set().
222 * This is necessary for correct lock ordering because
223 * thread_affinity_set() takes the task lock.
224 */
225 thread_mtx_unlock(thread);
226 return thread_affinity_set(thread, info->affinity_tag);
227 }
6d2010ae
A
228
229#if CONFIG_EMBEDDED
230 case THREAD_BACKGROUND_POLICY:
231 {
232 thread_background_policy_t info;
233
234 info = (thread_background_policy_t) policy_info;
235
236 thread_mtx_unlock(thread);
237 return mach_do_background_thread(thread, info->priority);
238 }
239#endif /* CONFIG_EMBEDDED */
240
1c79356b
A
241 default:
242 result = KERN_INVALID_ARGUMENT;
243 break;
244 }
245
91447636 246 thread_mtx_unlock(thread);
1c79356b
A
247 return (result);
248}
249
0b4e3aa0
A
250static void
251thread_recompute_priority(
252 thread_t thread)
253{
254 integer_t priority;
255
6d2010ae 256 if (thread->sched_mode == TH_MODE_REALTIME)
55e303ae 257 priority = BASEPRI_RTQUEUES;
0b4e3aa0
A
258 else {
259 if (thread->importance > MAXPRI)
260 priority = MAXPRI;
261 else
262 if (thread->importance < -MAXPRI)
263 priority = -MAXPRI;
264 else
265 priority = thread->importance;
266
267 priority += thread->task_priority;
268
269 if (priority > thread->max_priority)
270 priority = thread->max_priority;
271 else
272 if (priority < MINPRI)
273 priority = MINPRI;
6d2010ae
A
274#if CONFIG_EMBEDDED
275 /* No one can have a base priority less than MAXPRI_THROTTLE */
276 if (priority < MAXPRI_THROTTLE)
277 priority = MAXPRI_THROTTLE;
278#endif /* CONFIG_EMBEDDED */
0b4e3aa0
A
279 }
280
9bccf70c 281 set_priority(thread, priority);
0b4e3aa0
A
282}
283
6d2010ae
A
284#if CONFIG_EMBEDDED
285static void
286thread_throttle(
287 thread_t thread,
288 integer_t task_priority)
289{
316670eb
A
290 if ((!(thread->sched_flags & TH_SFLAG_THROTTLED)
291 || (thread->sched_flags & TH_SFLAG_PENDING_THROTTLE_PROMOTION))
292 && (task_priority <= MAXPRI_THROTTLE)) {
293
294 /* Kill a promotion if it was in flight */
295 thread->sched_flags &= ~TH_SFLAG_PENDING_THROTTLE_PROMOTION;
296
297 if (!(thread->sched_flags & TH_SFLAG_THROTTLED)) {
298 /*
299 * Set the pending bit so that we can switch runqueues
300 * (potentially) at a later time safely
301 */
302 thread->sched_flags |= TH_SFLAG_PENDING_THROTTLE_DEMOTION;
6d2010ae 303 }
6d2010ae 304 }
316670eb
A
305 else if (((thread->sched_flags & TH_SFLAG_THROTTLED)
306 || (thread->sched_flags & TH_SFLAG_PENDING_THROTTLE_DEMOTION))
307 && (task_priority > MAXPRI_THROTTLE)) {
6d2010ae 308
316670eb
A
309 /* Kill a demotion if it was in flight */
310 thread->sched_flags &= ~TH_SFLAG_PENDING_THROTTLE_DEMOTION;
6d2010ae 311
316670eb
A
312 if (thread->sched_flags & TH_SFLAG_THROTTLED) {
313 thread->sched_flags |= TH_SFLAG_PENDING_THROTTLE_PROMOTION;
6d2010ae 314 }
6d2010ae
A
315 }
316}
317#endif
318
0b4e3aa0
A
319void
320thread_task_priority(
321 thread_t thread,
322 integer_t priority,
323 integer_t max_priority)
324{
325 spl_t s;
326
327 assert(thread != THREAD_NULL);
328
329 s = splsched();
330 thread_lock(thread);
331
6d2010ae
A
332#if CONFIG_EMBEDDED
333 thread_throttle(thread, priority);
334#endif
335
0b4e3aa0
A
336 thread->task_priority = priority;
337 thread->max_priority = max_priority;
338
339 thread_recompute_priority(thread);
340
341 thread_unlock(thread);
342 splx(s);
343}
344
91447636
A
345void
346thread_policy_reset(
347 thread_t thread)
348{
2d21ac55
A
349 spl_t s;
350
351 s = splsched();
352 thread_lock(thread);
353
6d2010ae
A
354 if (!(thread->sched_flags & TH_SFLAG_DEMOTED_MASK)) {
355 sched_mode_t oldmode = thread->sched_mode;
356
357 thread->sched_mode = SCHED(initial_thread_sched_mode)(thread->task);
91447636 358
6d2010ae 359 if ((oldmode != TH_MODE_TIMESHARE) && (thread->sched_mode == TH_MODE_TIMESHARE)) {
91447636 360
2d21ac55
A
361 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
362 sched_share_incr();
91447636
A
363 }
364 }
365 else {
316670eb 366 thread->sched_mode = thread->saved_mode;
6d2010ae
A
367 thread->saved_mode = TH_MODE_NONE;
368 thread->sched_flags &= ~TH_SFLAG_DEMOTED_MASK;
91447636
A
369 }
370
371 thread->importance = 0;
372
373 thread_recompute_priority(thread);
2d21ac55
A
374
375 thread_unlock(thread);
376 splx(s);
91447636
A
377}
378
1c79356b
A
379kern_return_t
380thread_policy_get(
91447636 381 thread_t thread,
1c79356b
A
382 thread_policy_flavor_t flavor,
383 thread_policy_t policy_info,
384 mach_msg_type_number_t *count,
385 boolean_t *get_default)
386{
387 kern_return_t result = KERN_SUCCESS;
1c79356b
A
388 spl_t s;
389
91447636 390 if (thread == THREAD_NULL)
1c79356b
A
391 return (KERN_INVALID_ARGUMENT);
392
91447636
A
393 thread_mtx_lock(thread);
394 if (!thread->active) {
395 thread_mtx_unlock(thread);
1c79356b
A
396
397 return (KERN_TERMINATED);
398 }
399
1c79356b
A
400 switch (flavor) {
401
0b4e3aa0
A
402 case THREAD_EXTENDED_POLICY:
403 {
404 boolean_t timeshare = TRUE;
1c79356b 405
0b4e3aa0
A
406 if (!(*get_default)) {
407 s = splsched();
408 thread_lock(thread);
409
6d2010ae
A
410 if ( (thread->sched_mode != TH_MODE_REALTIME) &&
411 (thread->saved_mode != TH_MODE_REALTIME) ) {
412 if (!(thread->sched_flags & TH_SFLAG_DEMOTED_MASK))
413 timeshare = (thread->sched_mode == TH_MODE_TIMESHARE) != 0;
0b4e3aa0 414 else
6d2010ae 415 timeshare = (thread->saved_mode == TH_MODE_TIMESHARE) != 0;
0b4e3aa0
A
416 }
417 else
418 *get_default = TRUE;
419
420 thread_unlock(thread);
421 splx(s);
422 }
423
424 if (*count >= THREAD_EXTENDED_POLICY_COUNT) {
425 thread_extended_policy_t info;
426
427 info = (thread_extended_policy_t)policy_info;
428 info->timeshare = timeshare;
429 }
1c79356b 430
1c79356b 431 break;
0b4e3aa0 432 }
1c79356b
A
433
434 case THREAD_TIME_CONSTRAINT_POLICY:
435 {
436 thread_time_constraint_policy_t info;
437
438 if (*count < THREAD_TIME_CONSTRAINT_POLICY_COUNT) {
439 result = KERN_INVALID_ARGUMENT;
440 break;
441 }
442
443 info = (thread_time_constraint_policy_t)policy_info;
444
0b4e3aa0
A
445 if (!(*get_default)) {
446 s = splsched();
447 thread_lock(thread);
1c79356b 448
6d2010ae
A
449 if ( (thread->sched_mode == TH_MODE_REALTIME) ||
450 (thread->saved_mode == TH_MODE_REALTIME) ) {
0b4e3aa0
A
451 info->period = thread->realtime.period;
452 info->computation = thread->realtime.computation;
453 info->constraint = thread->realtime.constraint;
454 info->preemptible = thread->realtime.preemptible;
455 }
456 else
457 *get_default = TRUE;
1c79356b 458
0b4e3aa0
A
459 thread_unlock(thread);
460 splx(s);
461 }
1c79356b 462
0b4e3aa0 463 if (*get_default) {
1c79356b 464 info->period = 0;
6d2010ae
A
465 info->computation = default_timeshare_computation;
466 info->constraint = default_timeshare_constraint;
1c79356b
A
467 info->preemptible = TRUE;
468 }
469
1c79356b
A
470 break;
471 }
472
473 case THREAD_PRECEDENCE_POLICY:
474 {
475 thread_precedence_policy_t info;
476
477 if (*count < THREAD_PRECEDENCE_POLICY_COUNT) {
478 result = KERN_INVALID_ARGUMENT;
479 break;
480 }
481
482 info = (thread_precedence_policy_t)policy_info;
483
0b4e3aa0 484 if (!(*get_default)) {
1c79356b
A
485 s = splsched();
486 thread_lock(thread);
487
488 info->importance = thread->importance;
489
490 thread_unlock(thread);
491 splx(s);
492 }
0b4e3aa0
A
493 else
494 info->importance = 0;
1c79356b
A
495
496 break;
497 }
498
2d21ac55
A
499 case THREAD_AFFINITY_POLICY:
500 {
501 thread_affinity_policy_t info;
502
503 if (!thread_affinity_is_supported()) {
504 result = KERN_NOT_SUPPORTED;
505 break;
506 }
507 if (*count < THREAD_AFFINITY_POLICY_COUNT) {
508 result = KERN_INVALID_ARGUMENT;
509 break;
510 }
511
512 info = (thread_affinity_policy_t)policy_info;
513
514 if (!(*get_default))
515 info->affinity_tag = thread_affinity_get(thread);
516 else
517 info->affinity_tag = THREAD_AFFINITY_TAG_NULL;
518
519 break;
520 }
521
1c79356b
A
522 default:
523 result = KERN_INVALID_ARGUMENT;
524 break;
525 }
526
91447636 527 thread_mtx_unlock(thread);
1c79356b
A
528
529 return (result);
530}