2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/mach_types.h>
30 #include <mach/thread_act_server.h>
32 #include <kern/kern_types.h>
33 #include <kern/processor.h>
34 #include <kern/thread.h>
35 #include <kern/affinity.h>
38 thread_recompute_priority(
42 extern void proc_get_thread_policy(thread_t thread
, thread_policy_state_t info
);
47 thread_policy_flavor_t flavor
,
48 thread_policy_t policy_info
,
49 mach_msg_type_number_t count
)
52 if (thread
== THREAD_NULL
)
53 return (KERN_INVALID_ARGUMENT
);
55 if (thread
->static_param
)
56 return (KERN_SUCCESS
);
58 return (thread_policy_set_internal(thread
, flavor
, policy_info
, count
));
62 thread_policy_set_internal(
64 thread_policy_flavor_t flavor
,
65 thread_policy_t policy_info
,
66 mach_msg_type_number_t count
)
68 kern_return_t result
= KERN_SUCCESS
;
71 thread_mtx_lock(thread
);
72 if (!thread
->active
) {
73 thread_mtx_unlock(thread
);
75 return (KERN_TERMINATED
);
79 case THREAD_EXTENDED_POLICY
:
81 boolean_t timeshare
= TRUE
;
83 if (count
>= THREAD_EXTENDED_POLICY_COUNT
) {
84 thread_extended_policy_t info
;
86 info
= (thread_extended_policy_t
)policy_info
;
87 timeshare
= info
->timeshare
;
90 if (!SCHED(supports_timeshare_mode
)())
96 if (!(thread
->sched_flags
& TH_SFLAG_DEMOTED_MASK
)) {
97 integer_t oldmode
= (thread
->sched_mode
== TH_MODE_TIMESHARE
);
100 thread
->sched_mode
= TH_MODE_TIMESHARE
;
103 if ((thread
->state
& (TH_RUN
|TH_IDLE
)) == TH_RUN
) {
106 if (thread
->max_priority
<= MAXPRI_THROTTLE
)
107 sched_background_incr();
112 thread
->sched_mode
= TH_MODE_FIXED
;
115 if ((thread
->state
& (TH_RUN
|TH_IDLE
)) == TH_RUN
) {
116 if (thread
->max_priority
<= MAXPRI_THROTTLE
)
117 sched_background_decr();
124 thread_recompute_priority(thread
);
129 thread
->saved_mode
= TH_MODE_TIMESHARE
;
131 thread
->saved_mode
= TH_MODE_FIXED
;
134 thread_unlock(thread
);
140 case THREAD_TIME_CONSTRAINT_POLICY
:
142 thread_time_constraint_policy_t info
;
144 if (count
< THREAD_TIME_CONSTRAINT_POLICY_COUNT
) {
145 result
= KERN_INVALID_ARGUMENT
;
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
;
160 thread
->realtime
.period
= info
->period
;
161 thread
->realtime
.computation
= info
->computation
;
162 thread
->realtime
.constraint
= info
->constraint
;
163 thread
->realtime
.preemptible
= info
->preemptible
;
165 if (thread
->sched_flags
& TH_SFLAG_DEMOTED_MASK
) {
166 thread
->saved_mode
= TH_MODE_REALTIME
;
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();
177 thread
->sched_mode
= TH_MODE_REALTIME
;
178 thread_recompute_priority(thread
);
181 thread_unlock(thread
);
187 case THREAD_PRECEDENCE_POLICY
:
189 thread_precedence_policy_t info
;
191 if (count
< THREAD_PRECEDENCE_POLICY_COUNT
) {
192 result
= KERN_INVALID_ARGUMENT
;
195 info
= (thread_precedence_policy_t
)policy_info
;
200 thread
->importance
= info
->importance
;
202 thread_recompute_priority(thread
);
204 thread_unlock(thread
);
210 case THREAD_AFFINITY_POLICY
:
212 thread_affinity_policy_t info
;
214 if (!thread_affinity_is_supported()) {
215 result
= KERN_NOT_SUPPORTED
;
218 if (count
< THREAD_AFFINITY_POLICY_COUNT
) {
219 result
= KERN_INVALID_ARGUMENT
;
223 info
= (thread_affinity_policy_t
) policy_info
;
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.
230 thread_mtx_unlock(thread
);
231 return thread_affinity_set(thread
, info
->affinity_tag
);
236 result
= KERN_INVALID_ARGUMENT
;
240 thread_mtx_unlock(thread
);
245 thread_recompute_priority(
250 if (thread
->sched_mode
== TH_MODE_REALTIME
)
251 priority
= BASEPRI_RTQUEUES
;
253 if (thread
->importance
> MAXPRI
)
256 if (thread
->importance
< -MAXPRI
)
259 priority
= thread
->importance
;
261 priority
+= thread
->task_priority
;
263 if (priority
> thread
->max_priority
)
264 priority
= thread
->max_priority
;
266 if (priority
< MINPRI
)
270 set_priority(thread
, priority
);
275 thread_task_priority(
278 integer_t max_priority
)
282 assert(thread
!= THREAD_NULL
);
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();
297 thread
->task_priority
= priority
;
298 thread
->max_priority
= max_priority
;
300 thread_recompute_priority(thread
);
302 thread_unlock(thread
);
315 if (!(thread
->sched_flags
& TH_SFLAG_DEMOTED_MASK
)) {
316 sched_mode_t oldmode
= thread
->sched_mode
;
318 thread
->sched_mode
= SCHED(initial_thread_sched_mode
)(thread
->task
);
320 if ((oldmode
!= TH_MODE_TIMESHARE
) && (thread
->sched_mode
== TH_MODE_TIMESHARE
)) {
322 if ((thread
->state
& (TH_RUN
|TH_IDLE
)) == TH_RUN
) {
325 if (thread
->max_priority
<= MAXPRI_THROTTLE
)
326 sched_background_incr();
331 thread
->sched_mode
= thread
->saved_mode
;
332 thread
->saved_mode
= TH_MODE_NONE
;
333 thread
->sched_flags
&= ~TH_SFLAG_DEMOTED_MASK
;
336 thread
->importance
= 0;
338 thread_recompute_priority(thread
);
340 thread_unlock(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
)
352 kern_return_t result
= KERN_SUCCESS
;
355 if (thread
== THREAD_NULL
)
356 return (KERN_INVALID_ARGUMENT
);
358 thread_mtx_lock(thread
);
359 if (!thread
->active
) {
360 thread_mtx_unlock(thread
);
362 return (KERN_TERMINATED
);
367 case THREAD_EXTENDED_POLICY
:
369 boolean_t timeshare
= TRUE
;
371 if (!(*get_default
)) {
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;
380 timeshare
= (thread
->saved_mode
== TH_MODE_TIMESHARE
) != 0;
385 thread_unlock(thread
);
389 if (*count
>= THREAD_EXTENDED_POLICY_COUNT
) {
390 thread_extended_policy_t info
;
392 info
= (thread_extended_policy_t
)policy_info
;
393 info
->timeshare
= timeshare
;
399 case THREAD_TIME_CONSTRAINT_POLICY
:
401 thread_time_constraint_policy_t info
;
403 if (*count
< THREAD_TIME_CONSTRAINT_POLICY_COUNT
) {
404 result
= KERN_INVALID_ARGUMENT
;
408 info
= (thread_time_constraint_policy_t
)policy_info
;
410 if (!(*get_default
)) {
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
;
424 thread_unlock(thread
);
430 info
->computation
= default_timeshare_computation
;
431 info
->constraint
= default_timeshare_constraint
;
432 info
->preemptible
= TRUE
;
438 case THREAD_PRECEDENCE_POLICY
:
440 thread_precedence_policy_t info
;
442 if (*count
< THREAD_PRECEDENCE_POLICY_COUNT
) {
443 result
= KERN_INVALID_ARGUMENT
;
447 info
= (thread_precedence_policy_t
)policy_info
;
449 if (!(*get_default
)) {
453 info
->importance
= thread
->importance
;
455 thread_unlock(thread
);
459 info
->importance
= 0;
464 case THREAD_AFFINITY_POLICY
:
466 thread_affinity_policy_t info
;
468 if (!thread_affinity_is_supported()) {
469 result
= KERN_NOT_SUPPORTED
;
472 if (*count
< THREAD_AFFINITY_POLICY_COUNT
) {
473 result
= KERN_INVALID_ARGUMENT
;
477 info
= (thread_affinity_policy_t
)policy_info
;
480 info
->affinity_tag
= thread_affinity_get(thread
);
482 info
->affinity_tag
= THREAD_AFFINITY_TAG_NULL
;
487 case THREAD_POLICY_STATE
:
489 thread_policy_state_t info
;
491 if (*count
< THREAD_POLICY_STATE_COUNT
) {
492 result
= KERN_INVALID_ARGUMENT
;
496 /* Only root can get this info */
497 if (current_task()->sec_token
.val
[0] != 0) {
498 result
= KERN_PROTECTION_FAILURE
;
502 info
= (thread_policy_state_t
)policy_info
;
504 if (!(*get_default
)) {
506 * Unlock the thread mutex and directly return.
507 * This is necessary because proc_get_thread_policy()
508 * takes the task lock.
510 thread_mtx_unlock(thread
);
511 proc_get_thread_policy(thread
, info
);
524 result
= KERN_INVALID_ARGUMENT
;
528 thread_mtx_unlock(thread
);