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