]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/thread_policy.c
xnu-1504.15.3.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
43 kern_return_t
44 thread_policy_set(
45 thread_t thread,
46 thread_policy_flavor_t flavor,
47 thread_policy_t policy_info,
48 mach_msg_type_number_t count)
49 {
50
51 if (thread == THREAD_NULL)
52 return (KERN_INVALID_ARGUMENT);
53
54 if (thread->static_param)
55 return (KERN_SUCCESS);
56
57 return (thread_policy_set_internal(thread, flavor, policy_info, count));
58 }
59
60 kern_return_t
61 thread_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
70 thread_mtx_lock(thread);
71 if (!thread->active) {
72 thread_mtx_unlock(thread);
73
74 return (KERN_TERMINATED);
75 }
76 switch (flavor) {
77
78 case THREAD_EXTENDED_POLICY:
79 {
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 }
88
89 s = splsched();
90 thread_lock(thread);
91
92 if (!(thread->sched_mode & TH_MODE_FAILSAFE)) {
93 integer_t oldmode = (thread->sched_mode & TH_MODE_TIMESHARE);
94
95 thread->sched_mode &= ~TH_MODE_REALTIME;
96
97 if (timeshare && !oldmode) {
98 thread->sched_mode |= TH_MODE_TIMESHARE;
99
100 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
101 sched_share_incr();
102 }
103 else
104 if (!timeshare && oldmode) {
105 thread->sched_mode &= ~TH_MODE_TIMESHARE;
106
107 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
108 sched_share_decr();
109 }
110
111 thread_recompute_priority(thread);
112 }
113 else {
114 thread->safe_mode &= ~TH_MODE_REALTIME;
115
116 if (timeshare)
117 thread->safe_mode |= TH_MODE_TIMESHARE;
118 else
119 thread->safe_mode &= ~TH_MODE_TIMESHARE;
120 }
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;
138 if ( info->constraint < info->computation ||
139 info->computation > max_rt_quantum ||
140 info->computation < min_rt_quantum ) {
141 result = KERN_INVALID_ARGUMENT;
142 break;
143 }
144
145 s = splsched();
146 thread_lock(thread);
147
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
153 if (!(thread->sched_mode & TH_MODE_FAILSAFE)) {
154 if (thread->sched_mode & TH_MODE_TIMESHARE) {
155 thread->sched_mode &= ~TH_MODE_TIMESHARE;
156
157 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
158 sched_share_decr();
159 }
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 }
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 }
182 info = (thread_precedence_policy_t)policy_info;
183
184 s = splsched();
185 thread_lock(thread);
186
187 thread->importance = info->importance;
188
189 thread_recompute_priority(thread);
190
191 thread_unlock(thread);
192 splx(s);
193
194 break;
195 }
196
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 }
220 default:
221 result = KERN_INVALID_ARGUMENT;
222 break;
223 }
224
225 thread_mtx_unlock(thread);
226 return (result);
227 }
228
229 static void
230 thread_recompute_priority(
231 thread_t thread)
232 {
233 integer_t priority;
234
235 if (thread->sched_mode & TH_MODE_REALTIME)
236 priority = BASEPRI_RTQUEUES;
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
255 set_priority(thread, priority);
256 }
257
258 void
259 thread_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
280 void
281 thread_policy_reset(
282 thread_t thread)
283 {
284 spl_t s;
285
286 s = splsched();
287 thread_lock(thread);
288
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
295 if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
296 sched_share_incr();
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);
307
308 thread_unlock(thread);
309 splx(s);
310 }
311
312 kern_return_t
313 thread_policy_get(
314 thread_t thread,
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;
321 spl_t s;
322
323 if (thread == THREAD_NULL)
324 return (KERN_INVALID_ARGUMENT);
325
326 thread_mtx_lock(thread);
327 if (!thread->active) {
328 thread_mtx_unlock(thread);
329
330 return (KERN_TERMINATED);
331 }
332
333 switch (flavor) {
334
335 case THREAD_EXTENDED_POLICY:
336 {
337 boolean_t timeshare = TRUE;
338
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 }
363
364 break;
365 }
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
378 if (!(*get_default)) {
379 s = splsched();
380 thread_lock(thread);
381
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;
391
392 thread_unlock(thread);
393 splx(s);
394 }
395
396 if (*get_default) {
397 info->period = 0;
398 info->computation = std_quantum / 2;
399 info->constraint = std_quantum;
400 info->preemptible = TRUE;
401 }
402
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
417 if (!(*get_default)) {
418 s = splsched();
419 thread_lock(thread);
420
421 info->importance = thread->importance;
422
423 thread_unlock(thread);
424 splx(s);
425 }
426 else
427 info->importance = 0;
428
429 break;
430 }
431
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
455 default:
456 result = KERN_INVALID_ARGUMENT;
457 break;
458 }
459
460 thread_mtx_unlock(thread);
461
462 return (result);
463 }