xref: /xnu-10002.1.13/osfmk/kern/mk_sp.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
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  */
71 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)72 thread_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 
89 	if (invalid_policy(policy)) {
90 		return KERN_INVALID_ARGUMENT;
91 	}
92 
93 	switch (policy) {
94 	case POLICY_RR:
95 	{
96 		policy_rr_base_t                rr_base = (policy_rr_base_t) base;
97 		policy_rr_limit_t               rr_limit = (policy_rr_limit_t) limit;
98 
99 		if (base_count != POLICY_RR_BASE_COUNT ||
100 		    limit_count != POLICY_RR_LIMIT_COUNT) {
101 			result = KERN_INVALID_ARGUMENT;
102 			break;
103 		}
104 
105 		bas = rr_base->base_priority;
106 		max = rr_limit->max_priority;
107 		if (invalid_pri(bas) || invalid_pri(max)) {
108 			result = KERN_INVALID_ARGUMENT;
109 			break;
110 		}
111 
112 		break;
113 	}
114 
115 	case POLICY_FIFO:
116 	{
117 		policy_fifo_base_t              fifo_base = (policy_fifo_base_t) base;
118 		policy_fifo_limit_t             fifo_limit = (policy_fifo_limit_t) limit;
119 
120 		if (base_count != POLICY_FIFO_BASE_COUNT ||
121 		    limit_count != POLICY_FIFO_LIMIT_COUNT) {
122 			result = KERN_INVALID_ARGUMENT;
123 			break;
124 		}
125 
126 		bas = fifo_base->base_priority;
127 		max = fifo_limit->max_priority;
128 		if (invalid_pri(bas) || invalid_pri(max)) {
129 			result = KERN_INVALID_ARGUMENT;
130 			break;
131 		}
132 
133 		break;
134 	}
135 
136 	case POLICY_TIMESHARE:
137 	{
138 		policy_timeshare_base_t         ts_base = (policy_timeshare_base_t) base;
139 		policy_timeshare_limit_t        ts_limit =
140 		    (policy_timeshare_limit_t) limit;
141 
142 		if (base_count != POLICY_TIMESHARE_BASE_COUNT ||
143 		    limit_count != POLICY_TIMESHARE_LIMIT_COUNT) {
144 			result = KERN_INVALID_ARGUMENT;
145 			break;
146 		}
147 
148 		bas = ts_base->base_priority;
149 		max = ts_limit->max_priority;
150 		if (invalid_pri(bas) || invalid_pri(max)) {
151 			result = KERN_INVALID_ARGUMENT;
152 			break;
153 		}
154 
155 		break;
156 	}
157 
158 	default:
159 		result = KERN_INVALID_POLICY;
160 	}
161 
162 	if (result != KERN_SUCCESS) {
163 		return result;
164 	}
165 
166 	/* Note that we do not pass on max priority. */
167 	if (result == KERN_SUCCESS) {
168 		result = thread_set_mode_and_absolute_pri(thread, policy, bas);
169 	}
170 
171 	return result;
172 }
173 
174 
175 /*
176  *      thread_policy
177  *
178  *	Set scheduling policy and parameters, both base and limit, for
179  *	the given thread. Policy must be a policy which is enabled for the
180  *	processor set. Change contained threads if requested.
181  */
182 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)183 thread_policy(
184 	thread_t                                thread,
185 	policy_t                                policy,
186 	policy_base_t                   base,
187 	mach_msg_type_number_t  count,
188 	boolean_t                               set_limit)
189 {
190 	kern_return_t                   result = KERN_SUCCESS;
191 	processor_set_t                 pset = &pset0;
192 	policy_limit_t                  limit = NULL;
193 	int                                             limcount = 0;
194 	policy_rr_limit_data_t                  rr_limit;
195 	policy_fifo_limit_data_t                fifo_limit;
196 	policy_timeshare_limit_data_t   ts_limit;
197 
198 	if (thread == THREAD_NULL) {
199 		return KERN_INVALID_ARGUMENT;
200 	}
201 
202 	thread_mtx_lock(thread);
203 
204 	if (invalid_policy(policy) ||
205 	    ((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0) {
206 		thread_mtx_unlock(thread);
207 
208 		return KERN_INVALID_POLICY;
209 	}
210 
211 	if (set_limit) {
212 		/*
213 		 *      Set scheduling limits to base priority.
214 		 */
215 		switch (policy) {
216 		case POLICY_RR:
217 		{
218 			policy_rr_base_t rr_base;
219 
220 			if (count != POLICY_RR_BASE_COUNT) {
221 				result = KERN_INVALID_ARGUMENT;
222 				break;
223 			}
224 
225 			limcount = POLICY_RR_LIMIT_COUNT;
226 			rr_base = (policy_rr_base_t) base;
227 			rr_limit.max_priority = rr_base->base_priority;
228 			limit = (policy_limit_t) &rr_limit;
229 
230 			break;
231 		}
232 
233 		case POLICY_FIFO:
234 		{
235 			policy_fifo_base_t fifo_base;
236 
237 			if (count != POLICY_FIFO_BASE_COUNT) {
238 				result = KERN_INVALID_ARGUMENT;
239 				break;
240 			}
241 
242 			limcount = POLICY_FIFO_LIMIT_COUNT;
243 			fifo_base = (policy_fifo_base_t) base;
244 			fifo_limit.max_priority = fifo_base->base_priority;
245 			limit = (policy_limit_t) &fifo_limit;
246 
247 			break;
248 		}
249 
250 		case POLICY_TIMESHARE:
251 		{
252 			policy_timeshare_base_t ts_base;
253 
254 			if (count != POLICY_TIMESHARE_BASE_COUNT) {
255 				result = KERN_INVALID_ARGUMENT;
256 				break;
257 			}
258 
259 			limcount = POLICY_TIMESHARE_LIMIT_COUNT;
260 			ts_base = (policy_timeshare_base_t) base;
261 			ts_limit.max_priority = ts_base->base_priority;
262 			limit = (policy_limit_t) &ts_limit;
263 
264 			break;
265 		}
266 
267 		default:
268 			result = KERN_INVALID_POLICY;
269 			break;
270 		}
271 	} else {
272 		/*
273 		 *	Use current scheduling limits. Ensure that the
274 		 *	new base priority will not exceed current limits.
275 		 */
276 		switch (policy) {
277 		case POLICY_RR:
278 		{
279 			policy_rr_base_t rr_base;
280 
281 			if (count != POLICY_RR_BASE_COUNT) {
282 				result = KERN_INVALID_ARGUMENT;
283 				break;
284 			}
285 
286 			limcount = POLICY_RR_LIMIT_COUNT;
287 			rr_base = (policy_rr_base_t) base;
288 			if (rr_base->base_priority > thread->max_priority) {
289 				result = KERN_POLICY_LIMIT;
290 				break;
291 			}
292 
293 			rr_limit.max_priority = thread->max_priority;
294 			limit = (policy_limit_t) &rr_limit;
295 
296 			break;
297 		}
298 
299 		case POLICY_FIFO:
300 		{
301 			policy_fifo_base_t fifo_base;
302 
303 			if (count != POLICY_FIFO_BASE_COUNT) {
304 				result = KERN_INVALID_ARGUMENT;
305 				break;
306 			}
307 
308 			limcount = POLICY_FIFO_LIMIT_COUNT;
309 			fifo_base = (policy_fifo_base_t) base;
310 			if (fifo_base->base_priority > thread->max_priority) {
311 				result = KERN_POLICY_LIMIT;
312 				break;
313 			}
314 
315 			fifo_limit.max_priority = thread->max_priority;
316 			limit = (policy_limit_t) &fifo_limit;
317 
318 			break;
319 		}
320 
321 		case POLICY_TIMESHARE:
322 		{
323 			policy_timeshare_base_t ts_base;
324 
325 			if (count != POLICY_TIMESHARE_BASE_COUNT) {
326 				result = KERN_INVALID_ARGUMENT;
327 				break;
328 			}
329 
330 			limcount = POLICY_TIMESHARE_LIMIT_COUNT;
331 			ts_base = (policy_timeshare_base_t) base;
332 			if (ts_base->base_priority > thread->max_priority) {
333 				result = KERN_POLICY_LIMIT;
334 				break;
335 			}
336 
337 			ts_limit.max_priority = thread->max_priority;
338 			limit = (policy_limit_t) &ts_limit;
339 
340 			break;
341 		}
342 
343 		default:
344 			result = KERN_INVALID_POLICY;
345 			break;
346 		}
347 	}
348 
349 	thread_mtx_unlock(thread);
350 
351 	if (result == KERN_SUCCESS) {
352 		result = thread_set_policy(thread, pset,
353 		    policy, base, count, limit, limcount);
354 	}
355 
356 	return result;
357 }
358