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
48#include <kern/syscall_subr.h>
49#include <mach/mach_host_server.h>
50#include <mach/mach_syscalls.h>
51
52#include <kern/misc_protos.h>
53#include <kern/spl.h>
54#include <kern/sched.h>
55#include <kern/sched_prim.h>
56#include <kern/assert.h>
57#include <kern/thread.h>
58#include <mach/mach_host_server.h>
59#include <mach/thread_act_server.h>
60#include <mach/host_priv_server.h>
61
62
63/*
64 *	thread_set_policy
65 *
66 *	Set scheduling policy and parameters, both base and limit, for
67 *	the given thread. Policy can be any policy implemented by the
68 *	processor set, whether enabled or not.
69 */
70kern_return_t
71thread_set_policy(
72	thread_t				thread,
73	processor_set_t			pset,
74	policy_t				policy,
75	policy_base_t			base,
76	mach_msg_type_number_t	base_count,
77	policy_limit_t			limit,
78	mach_msg_type_number_t	limit_count)
79{
80	int 					max, bas;
81	kern_return_t			result = KERN_SUCCESS;
82
83	if (	thread == THREAD_NULL			||
84			pset == PROCESSOR_SET_NULL || pset != &pset0)
85		return (KERN_INVALID_ARGUMENT);
86
87	if (invalid_policy(policy))
88		return(KERN_INVALID_ARGUMENT);
89
90	thread_mtx_lock(thread);
91
92	switch (policy) {
93
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		thread_mtx_unlock(thread);
164
165		return (result);
166	}
167
168	/* Note that we do not pass on max priority. */
169	if (result == KERN_SUCCESS) {
170	    result = thread_set_mode_and_absolute_pri(thread, policy, bas);
171	}
172
173	thread_mtx_unlock(thread);
174
175	return (result);
176}
177
178
179/*
180 * 	thread_policy
181 *
182 *	Set scheduling policy and parameters, both base and limit, for
183 *	the given thread. Policy must be a policy which is enabled for the
184 *	processor set. Change contained threads if requested.
185 */
186kern_return_t
187thread_policy(
188	thread_t				thread,
189	policy_t				policy,
190	policy_base_t			base,
191	mach_msg_type_number_t	count,
192	boolean_t				set_limit)
193{
194	kern_return_t			result = KERN_SUCCESS;
195	processor_set_t			pset = &pset0;
196	policy_limit_t			limit = NULL;
197	int						limcount = 0;
198	policy_rr_limit_data_t			rr_limit;
199	policy_fifo_limit_data_t		fifo_limit;
200	policy_timeshare_limit_data_t	ts_limit;
201
202	if (thread == THREAD_NULL)
203		return (KERN_INVALID_ARGUMENT);
204
205	thread_mtx_lock(thread);
206
207	if (	invalid_policy(policy)											||
208			((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0	) {
209		thread_mtx_unlock(thread);
210
211		return (KERN_INVALID_POLICY);
212	}
213
214	if (set_limit) {
215		/*
216	 	 * 	Set scheduling limits to base priority.
217		 */
218		switch (policy) {
219
220		case POLICY_RR:
221		{
222			policy_rr_base_t rr_base;
223
224			if (count != POLICY_RR_BASE_COUNT) {
225				result = KERN_INVALID_ARGUMENT;
226				break;
227			}
228
229			limcount = POLICY_RR_LIMIT_COUNT;
230			rr_base = (policy_rr_base_t) base;
231			rr_limit.max_priority = rr_base->base_priority;
232			limit = (policy_limit_t) &rr_limit;
233
234			break;
235		}
236
237		case POLICY_FIFO:
238		{
239			policy_fifo_base_t fifo_base;
240
241			if (count != POLICY_FIFO_BASE_COUNT) {
242				result = KERN_INVALID_ARGUMENT;
243				break;
244			}
245
246			limcount = POLICY_FIFO_LIMIT_COUNT;
247			fifo_base = (policy_fifo_base_t) base;
248			fifo_limit.max_priority = fifo_base->base_priority;
249			limit = (policy_limit_t) &fifo_limit;
250
251			break;
252		}
253
254		case POLICY_TIMESHARE:
255		{
256			policy_timeshare_base_t ts_base;
257
258			if (count != POLICY_TIMESHARE_BASE_COUNT) {
259				result = KERN_INVALID_ARGUMENT;
260				break;
261			}
262
263			limcount = POLICY_TIMESHARE_LIMIT_COUNT;
264			ts_base = (policy_timeshare_base_t) base;
265			ts_limit.max_priority = ts_base->base_priority;
266			limit = (policy_limit_t) &ts_limit;
267
268			break;
269		}
270
271		default:
272			result = KERN_INVALID_POLICY;
273			break;
274		}
275
276	}
277	else {
278		/*
279		 *	Use current scheduling limits. Ensure that the
280		 *	new base priority will not exceed current limits.
281		 */
282		switch (policy) {
283
284		case POLICY_RR:
285		{
286			policy_rr_base_t rr_base;
287
288			if (count != POLICY_RR_BASE_COUNT) {
289				result = KERN_INVALID_ARGUMENT;
290				break;
291			}
292
293			limcount = POLICY_RR_LIMIT_COUNT;
294			rr_base = (policy_rr_base_t) base;
295			if (rr_base->base_priority > thread->max_priority) {
296				result = KERN_POLICY_LIMIT;
297				break;
298			}
299
300			rr_limit.max_priority = thread->max_priority;
301			limit = (policy_limit_t) &rr_limit;
302
303			break;
304		}
305
306		case POLICY_FIFO:
307		{
308			policy_fifo_base_t fifo_base;
309
310			if (count != POLICY_FIFO_BASE_COUNT) {
311				result = KERN_INVALID_ARGUMENT;
312				break;
313			}
314
315			limcount = POLICY_FIFO_LIMIT_COUNT;
316			fifo_base = (policy_fifo_base_t) base;
317			if (fifo_base->base_priority > thread->max_priority) {
318				result = KERN_POLICY_LIMIT;
319				break;
320			}
321
322			fifo_limit.max_priority = thread->max_priority;
323			limit = (policy_limit_t) &fifo_limit;
324
325			break;
326		}
327
328		case POLICY_TIMESHARE:
329		{
330			policy_timeshare_base_t ts_base;
331
332			if (count != POLICY_TIMESHARE_BASE_COUNT) {
333				result = KERN_INVALID_ARGUMENT;
334				break;
335			}
336
337			limcount = POLICY_TIMESHARE_LIMIT_COUNT;
338			ts_base = (policy_timeshare_base_t) base;
339			if (ts_base->base_priority > thread->max_priority) {
340				result = KERN_POLICY_LIMIT;
341				break;
342			}
343
344			ts_limit.max_priority = thread->max_priority;
345			limit = (policy_limit_t) &ts_limit;
346
347			break;
348		}
349
350		default:
351			result = KERN_INVALID_POLICY;
352			break;
353		}
354
355	}
356
357	thread_mtx_unlock(thread);
358
359	if (result == KERN_SUCCESS)
360	    result = thread_set_policy(thread, pset,
361					 policy, base, count, limit, limcount);
362
363	return(result);
364}
365