xref: /xnu-12377.81.4/osfmk/kern/mk_sp.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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