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 * @OSF_COPYRIGHT@
30 *
31 */
32
33 /* The routines in this module are all obsolete */
34
35 #include <mach/boolean.h>
36 #include <mach/thread_switch.h>
37 #include <kern/ipc_kobject.h>
38 #include <kern/processor.h>
39 #include <kern/sched.h>
40 #include <kern/sched_prim.h>
41 #include <kern/spl.h>
42 #include <kern/task.h>
43 #include <kern/thread.h>
44 #include <mach/policy.h>
45 #include <kern/policy_internal.h>
46
47 #include <kern/syscall_subr.h>
48 #include <mach/mach_host_server.h>
49 #include <mach/mach_syscalls.h>
50
51 #include <kern/misc_protos.h>
52 #include <kern/spl.h>
53 #include <kern/sched.h>
54 #include <kern/sched_prim.h>
55 #include <kern/assert.h>
56 #include <kern/thread.h>
57 #include <mach/mach_host_server.h>
58 #include <mach/thread_act_server.h>
59 #include <mach/host_priv_server.h>
60
61
62 /*
63 * thread_set_policy
64 *
65 * Set scheduling policy and parameters, both base and limit, for
66 * the given thread. Policy can be any policy implemented by the
67 * processor set, whether enabled or not.
68 */
69 kern_return_t
thread_set_policy(thread_t thread,processor_set_t pset,policy_t policy,policy_base_t base,mach_msg_type_number_t base_count,policy_limit_t limit,mach_msg_type_number_t limit_count)70 thread_set_policy(
71 thread_t thread,
72 processor_set_t pset,
73 policy_t policy,
74 policy_base_t base,
75 mach_msg_type_number_t base_count,
76 policy_limit_t limit,
77 mach_msg_type_number_t limit_count)
78 {
79 int max, bas;
80 kern_return_t result = KERN_SUCCESS;
81
82 if (thread == THREAD_NULL ||
83 pset == PROCESSOR_SET_NULL || pset != sched_boot_pset) {
84 return KERN_INVALID_ARGUMENT;
85 }
86
87 if (invalid_policy(policy)) {
88 return KERN_INVALID_ARGUMENT;
89 }
90
91 switch (policy) {
92 case POLICY_RR:
93 {
94 policy_rr_base_t rr_base = (policy_rr_base_t) base;
95 policy_rr_limit_t rr_limit = (policy_rr_limit_t) limit;
96
97 if (base_count != POLICY_RR_BASE_COUNT ||
98 limit_count != POLICY_RR_LIMIT_COUNT) {
99 result = KERN_INVALID_ARGUMENT;
100 break;
101 }
102
103 bas = rr_base->base_priority;
104 max = rr_limit->max_priority;
105 if (invalid_pri(bas) || invalid_pri(max)) {
106 result = KERN_INVALID_ARGUMENT;
107 break;
108 }
109
110 break;
111 }
112
113 case POLICY_FIFO:
114 {
115 policy_fifo_base_t fifo_base = (policy_fifo_base_t) base;
116 policy_fifo_limit_t fifo_limit = (policy_fifo_limit_t) limit;
117
118 if (base_count != POLICY_FIFO_BASE_COUNT ||
119 limit_count != POLICY_FIFO_LIMIT_COUNT) {
120 result = KERN_INVALID_ARGUMENT;
121 break;
122 }
123
124 bas = fifo_base->base_priority;
125 max = fifo_limit->max_priority;
126 if (invalid_pri(bas) || invalid_pri(max)) {
127 result = KERN_INVALID_ARGUMENT;
128 break;
129 }
130
131 break;
132 }
133
134 case POLICY_TIMESHARE:
135 {
136 policy_timeshare_base_t ts_base = (policy_timeshare_base_t) base;
137 policy_timeshare_limit_t ts_limit =
138 (policy_timeshare_limit_t) limit;
139
140 if (base_count != POLICY_TIMESHARE_BASE_COUNT ||
141 limit_count != POLICY_TIMESHARE_LIMIT_COUNT) {
142 result = KERN_INVALID_ARGUMENT;
143 break;
144 }
145
146 bas = ts_base->base_priority;
147 max = ts_limit->max_priority;
148 if (invalid_pri(bas) || invalid_pri(max)) {
149 result = KERN_INVALID_ARGUMENT;
150 break;
151 }
152
153 break;
154 }
155
156 default:
157 result = KERN_INVALID_POLICY;
158 }
159
160 if (result != KERN_SUCCESS) {
161 return result;
162 }
163
164 /* Note that we do not pass on max priority. */
165 if (result == KERN_SUCCESS) {
166 result = thread_set_mode_and_absolute_pri(thread, policy, bas);
167 }
168
169 return result;
170 }
171
172
173 /*
174 * thread_policy
175 *
176 * Set scheduling policy and parameters, both base and limit, for
177 * the given thread. Policy must be a policy which is enabled for the
178 * processor set. Change contained threads if requested.
179 */
180 kern_return_t
thread_policy(thread_t thread,policy_t policy,policy_base_t base,mach_msg_type_number_t count,boolean_t set_limit)181 thread_policy(
182 thread_t thread,
183 policy_t policy,
184 policy_base_t base,
185 mach_msg_type_number_t count,
186 boolean_t set_limit)
187 {
188 kern_return_t result = KERN_SUCCESS;
189 processor_set_t pset = sched_boot_pset;
190 policy_limit_t limit = NULL;
191 int limcount = 0;
192 policy_rr_limit_data_t rr_limit;
193 policy_fifo_limit_data_t fifo_limit;
194 policy_timeshare_limit_data_t ts_limit;
195
196 if (thread == THREAD_NULL) {
197 return KERN_INVALID_ARGUMENT;
198 }
199
200 thread_mtx_lock(thread);
201
202 if (invalid_policy(policy) ||
203 ((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0) {
204 thread_mtx_unlock(thread);
205
206 return KERN_INVALID_POLICY;
207 }
208
209 if (set_limit) {
210 /*
211 * Set scheduling limits to base priority.
212 */
213 switch (policy) {
214 case POLICY_RR:
215 {
216 policy_rr_base_t rr_base;
217
218 if (count != POLICY_RR_BASE_COUNT) {
219 result = KERN_INVALID_ARGUMENT;
220 break;
221 }
222
223 limcount = POLICY_RR_LIMIT_COUNT;
224 rr_base = (policy_rr_base_t) base;
225 rr_limit.max_priority = rr_base->base_priority;
226 limit = (policy_limit_t) &rr_limit;
227
228 break;
229 }
230
231 case POLICY_FIFO:
232 {
233 policy_fifo_base_t fifo_base;
234
235 if (count != POLICY_FIFO_BASE_COUNT) {
236 result = KERN_INVALID_ARGUMENT;
237 break;
238 }
239
240 limcount = POLICY_FIFO_LIMIT_COUNT;
241 fifo_base = (policy_fifo_base_t) base;
242 fifo_limit.max_priority = fifo_base->base_priority;
243 limit = (policy_limit_t) &fifo_limit;
244
245 break;
246 }
247
248 case POLICY_TIMESHARE:
249 {
250 policy_timeshare_base_t ts_base;
251
252 if (count != POLICY_TIMESHARE_BASE_COUNT) {
253 result = KERN_INVALID_ARGUMENT;
254 break;
255 }
256
257 limcount = POLICY_TIMESHARE_LIMIT_COUNT;
258 ts_base = (policy_timeshare_base_t) base;
259 ts_limit.max_priority = ts_base->base_priority;
260 limit = (policy_limit_t) &ts_limit;
261
262 break;
263 }
264
265 default:
266 result = KERN_INVALID_POLICY;
267 break;
268 }
269 } else {
270 /*
271 * Use current scheduling limits. Ensure that the
272 * new base priority will not exceed current limits.
273 */
274 switch (policy) {
275 case POLICY_RR:
276 {
277 policy_rr_base_t rr_base;
278
279 if (count != POLICY_RR_BASE_COUNT) {
280 result = KERN_INVALID_ARGUMENT;
281 break;
282 }
283
284 limcount = POLICY_RR_LIMIT_COUNT;
285 rr_base = (policy_rr_base_t) base;
286 if (rr_base->base_priority > thread->max_priority) {
287 result = KERN_POLICY_LIMIT;
288 break;
289 }
290
291 rr_limit.max_priority = thread->max_priority;
292 limit = (policy_limit_t) &rr_limit;
293
294 break;
295 }
296
297 case POLICY_FIFO:
298 {
299 policy_fifo_base_t fifo_base;
300
301 if (count != POLICY_FIFO_BASE_COUNT) {
302 result = KERN_INVALID_ARGUMENT;
303 break;
304 }
305
306 limcount = POLICY_FIFO_LIMIT_COUNT;
307 fifo_base = (policy_fifo_base_t) base;
308 if (fifo_base->base_priority > thread->max_priority) {
309 result = KERN_POLICY_LIMIT;
310 break;
311 }
312
313 fifo_limit.max_priority = thread->max_priority;
314 limit = (policy_limit_t) &fifo_limit;
315
316 break;
317 }
318
319 case POLICY_TIMESHARE:
320 {
321 policy_timeshare_base_t ts_base;
322
323 if (count != POLICY_TIMESHARE_BASE_COUNT) {
324 result = KERN_INVALID_ARGUMENT;
325 break;
326 }
327
328 limcount = POLICY_TIMESHARE_LIMIT_COUNT;
329 ts_base = (policy_timeshare_base_t) base;
330 if (ts_base->base_priority > thread->max_priority) {
331 result = KERN_POLICY_LIMIT;
332 break;
333 }
334
335 ts_limit.max_priority = thread->max_priority;
336 limit = (policy_limit_t) &ts_limit;
337
338 break;
339 }
340
341 default:
342 result = KERN_INVALID_POLICY;
343 break;
344 }
345 }
346
347 thread_mtx_unlock(thread);
348
349 if (result == KERN_SUCCESS) {
350 result = thread_set_policy(thread, pset,
351 policy, base, count, limit, limcount);
352 }
353
354 return result;
355 }
356