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