]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/thread_policy.c
93a3287641d232eb4074544a5b2031c7d2d22e64
[apple/xnu.git] / osfmk / kern / thread_policy.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, 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
36 static void
37 thread_recompute_priority(
38 thread_t thread);
39
40 kern_return_t
41 thread_policy_set(
42 thread_t thread,
43 thread_policy_flavor_t flavor,
44 thread_policy_t policy_info,
45 mach_msg_type_number_t count)
46 {
47 kern_return_t result = KERN_SUCCESS;
48 spl_t s;
49
50 if (thread == THREAD_NULL)
51 return (KERN_INVALID_ARGUMENT);
52
53 thread_mtx_lock(thread);
54 if (!thread->active) {
55 thread_mtx_unlock(thread);
56
57 return (KERN_TERMINATED);
58 }
59
60 switch (flavor) {
61
62 case THREAD_EXTENDED_POLICY:
63 {
64 boolean_t timeshare = TRUE;
65
66 if (count >= THREAD_EXTENDED_POLICY_COUNT) {
67 thread_extended_policy_t info;
68
69 info = (thread_extended_policy_t)policy_info;
70 timeshare = info->timeshare;
71 }
72
73 s = splsched();
74 thread_lock(thread);
75
76 if (!(thread->sched_mode & TH_MODE_FAILSAFE)) {
77 integer_t oldmode = (thread->sched_mode & TH_MODE_TIMESHARE);
78
79 thread->sched_mode &= ~TH_MODE_REALTIME;
80
81 if (timeshare && !oldmode) {
82 thread->sched_mode |= TH_MODE_TIMESHARE;
83
84 if (thread->state & TH_RUN)
85 pset_share_incr(thread->processor_set);
86 }
87 else
88 if (!timeshare && oldmode) {
89 thread->sched_mode &= ~TH_MODE_TIMESHARE;
90
91 if (thread->state & TH_RUN)
92 pset_share_decr(thread->processor_set);
93 }
94
95 thread_recompute_priority(thread);
96 }
97 else {
98 thread->safe_mode &= ~TH_MODE_REALTIME;
99
100 if (timeshare)
101 thread->safe_mode |= TH_MODE_TIMESHARE;
102 else
103 thread->safe_mode &= ~TH_MODE_TIMESHARE;
104 }
105
106 thread_unlock(thread);
107 splx(s);
108
109 break;
110 }
111
112 case THREAD_TIME_CONSTRAINT_POLICY:
113 {
114 thread_time_constraint_policy_t info;
115
116 if (count < THREAD_TIME_CONSTRAINT_POLICY_COUNT) {
117 result = KERN_INVALID_ARGUMENT;
118 break;
119 }
120
121 info = (thread_time_constraint_policy_t)policy_info;
122 if ( info->constraint < info->computation ||
123 info->computation > max_rt_quantum ||
124 info->computation < min_rt_quantum ) {
125 result = KERN_INVALID_ARGUMENT;
126 break;
127 }
128
129 s = splsched();
130 thread_lock(thread);
131
132 thread->realtime.period = info->period;
133 thread->realtime.computation = info->computation;
134 thread->realtime.constraint = info->constraint;
135 thread->realtime.preemptible = info->preemptible;
136
137 if (!(thread->sched_mode & TH_MODE_FAILSAFE)) {
138 if (thread->sched_mode & TH_MODE_TIMESHARE) {
139 thread->sched_mode &= ~TH_MODE_TIMESHARE;
140
141 if (thread->state & TH_RUN)
142 pset_share_decr(thread->processor_set);
143 }
144 thread->sched_mode |= TH_MODE_REALTIME;
145 thread_recompute_priority(thread);
146 }
147 else {
148 thread->safe_mode &= ~TH_MODE_TIMESHARE;
149 thread->safe_mode |= TH_MODE_REALTIME;
150 }
151
152 thread_unlock(thread);
153 splx(s);
154
155 break;
156 }
157
158 case THREAD_PRECEDENCE_POLICY:
159 {
160 thread_precedence_policy_t info;
161
162 if (count < THREAD_PRECEDENCE_POLICY_COUNT) {
163 result = KERN_INVALID_ARGUMENT;
164 break;
165 }
166
167 info = (thread_precedence_policy_t)policy_info;
168
169 s = splsched();
170 thread_lock(thread);
171
172 thread->importance = info->importance;
173
174 thread_recompute_priority(thread);
175
176 thread_unlock(thread);
177 splx(s);
178
179 break;
180 }
181
182 default:
183 result = KERN_INVALID_ARGUMENT;
184 break;
185 }
186
187 thread_mtx_unlock(thread);
188
189 return (result);
190 }
191
192 static void
193 thread_recompute_priority(
194 thread_t thread)
195 {
196 integer_t priority;
197
198 if (thread->sched_mode & TH_MODE_REALTIME)
199 priority = BASEPRI_RTQUEUES;
200 else {
201 if (thread->importance > MAXPRI)
202 priority = MAXPRI;
203 else
204 if (thread->importance < -MAXPRI)
205 priority = -MAXPRI;
206 else
207 priority = thread->importance;
208
209 priority += thread->task_priority;
210
211 if (priority > thread->max_priority)
212 priority = thread->max_priority;
213 else
214 if (priority < MINPRI)
215 priority = MINPRI;
216 }
217
218 set_priority(thread, priority);
219 }
220
221 void
222 thread_task_priority(
223 thread_t thread,
224 integer_t priority,
225 integer_t max_priority)
226 {
227 spl_t s;
228
229 assert(thread != THREAD_NULL);
230
231 s = splsched();
232 thread_lock(thread);
233
234 thread->task_priority = priority;
235 thread->max_priority = max_priority;
236
237 thread_recompute_priority(thread);
238
239 thread_unlock(thread);
240 splx(s);
241 }
242
243 void
244 thread_policy_reset(
245 thread_t thread)
246 {
247 if (!(thread->sched_mode & TH_MODE_FAILSAFE)) {
248 thread->sched_mode &= ~TH_MODE_REALTIME;
249
250 if (!(thread->sched_mode & TH_MODE_TIMESHARE)) {
251 thread->sched_mode |= TH_MODE_TIMESHARE;
252
253 if (thread->state & TH_RUN)
254 pset_share_incr(thread->processor_set);
255 }
256 }
257 else {
258 thread->safe_mode = 0;
259 thread->sched_mode &= ~TH_MODE_FAILSAFE;
260 }
261
262 thread->importance = 0;
263
264 thread_recompute_priority(thread);
265 }
266
267 kern_return_t
268 thread_policy_get(
269 thread_t thread,
270 thread_policy_flavor_t flavor,
271 thread_policy_t policy_info,
272 mach_msg_type_number_t *count,
273 boolean_t *get_default)
274 {
275 kern_return_t result = KERN_SUCCESS;
276 spl_t s;
277
278 if (thread == THREAD_NULL)
279 return (KERN_INVALID_ARGUMENT);
280
281 thread_mtx_lock(thread);
282 if (!thread->active) {
283 thread_mtx_unlock(thread);
284
285 return (KERN_TERMINATED);
286 }
287
288 switch (flavor) {
289
290 case THREAD_EXTENDED_POLICY:
291 {
292 boolean_t timeshare = TRUE;
293
294 if (!(*get_default)) {
295 s = splsched();
296 thread_lock(thread);
297
298 if ( !(thread->sched_mode & TH_MODE_REALTIME) &&
299 !(thread->safe_mode & TH_MODE_REALTIME) ) {
300 if (!(thread->sched_mode & TH_MODE_FAILSAFE))
301 timeshare = (thread->sched_mode & TH_MODE_TIMESHARE) != 0;
302 else
303 timeshare = (thread->safe_mode & TH_MODE_TIMESHARE) != 0;
304 }
305 else
306 *get_default = TRUE;
307
308 thread_unlock(thread);
309 splx(s);
310 }
311
312 if (*count >= THREAD_EXTENDED_POLICY_COUNT) {
313 thread_extended_policy_t info;
314
315 info = (thread_extended_policy_t)policy_info;
316 info->timeshare = timeshare;
317 }
318
319 break;
320 }
321
322 case THREAD_TIME_CONSTRAINT_POLICY:
323 {
324 thread_time_constraint_policy_t info;
325
326 if (*count < THREAD_TIME_CONSTRAINT_POLICY_COUNT) {
327 result = KERN_INVALID_ARGUMENT;
328 break;
329 }
330
331 info = (thread_time_constraint_policy_t)policy_info;
332
333 if (!(*get_default)) {
334 s = splsched();
335 thread_lock(thread);
336
337 if ( (thread->sched_mode & TH_MODE_REALTIME) ||
338 (thread->safe_mode & TH_MODE_REALTIME) ) {
339 info->period = thread->realtime.period;
340 info->computation = thread->realtime.computation;
341 info->constraint = thread->realtime.constraint;
342 info->preemptible = thread->realtime.preemptible;
343 }
344 else
345 *get_default = TRUE;
346
347 thread_unlock(thread);
348 splx(s);
349 }
350
351 if (*get_default) {
352 info->period = 0;
353 info->computation = std_quantum / 2;
354 info->constraint = std_quantum;
355 info->preemptible = TRUE;
356 }
357
358 break;
359 }
360
361 case THREAD_PRECEDENCE_POLICY:
362 {
363 thread_precedence_policy_t info;
364
365 if (*count < THREAD_PRECEDENCE_POLICY_COUNT) {
366 result = KERN_INVALID_ARGUMENT;
367 break;
368 }
369
370 info = (thread_precedence_policy_t)policy_info;
371
372 if (!(*get_default)) {
373 s = splsched();
374 thread_lock(thread);
375
376 info->importance = thread->importance;
377
378 thread_unlock(thread);
379 splx(s);
380 }
381 else
382 info->importance = 0;
383
384 break;
385 }
386
387 default:
388 result = KERN_INVALID_ARGUMENT;
389 break;
390 }
391
392 thread_mtx_unlock(thread);
393
394 return (result);
395 }