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