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