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