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 *	thread_policy_common:
64 *
65 *	Set scheduling policy & priority for thread.
66 */
67static kern_return_t
68thread_policy_common(
69	thread_t		thread,
70	integer_t		policy,
71	integer_t		priority)
72{
73	spl_t			s;
74
75	if (	thread == THREAD_NULL		||
76			invalid_policy(policy)		)
77		return(KERN_INVALID_ARGUMENT);
78
79	if (thread->static_param)
80		return (KERN_SUCCESS);
81
82	if ((policy == POLICY_TIMESHARE)
83		&& !SCHED(supports_timeshare_mode)())
84		policy = TH_MODE_FIXED;
85
86	s = splsched();
87	thread_lock(thread);
88
89	if (	(thread->sched_mode != TH_MODE_REALTIME)	&&
90			(thread->saved_mode != TH_MODE_REALTIME)		) {
91		if (!(thread->sched_flags & TH_SFLAG_DEMOTED_MASK)) {
92			boolean_t	oldmode = thread->sched_mode == TH_MODE_TIMESHARE;
93
94			if (policy == POLICY_TIMESHARE && !oldmode) {
95				thread->sched_mode = TH_MODE_TIMESHARE;
96
97				if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
98					sched_share_incr();
99			}
100			else
101			if (policy != POLICY_TIMESHARE && oldmode) {
102				thread->sched_mode = TH_MODE_FIXED;
103
104				if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN)
105					sched_share_decr();
106			}
107		}
108		else {
109			if (policy == POLICY_TIMESHARE)
110				thread->saved_mode = TH_MODE_TIMESHARE;
111			else
112				thread->saved_mode = TH_MODE_FIXED;
113		}
114
115		if (priority >= thread->max_priority)
116			priority = thread->max_priority - thread->task_priority;
117		else
118		if (priority >= MINPRI_KERNEL)
119			priority -= MINPRI_KERNEL;
120		else
121		if (priority >= MINPRI_RESERVED)
122			priority -= MINPRI_RESERVED;
123		else
124			priority -= BASEPRI_DEFAULT;
125
126		priority += thread->task_priority;
127
128		if (priority > thread->max_priority)
129			priority = thread->max_priority;
130		else
131		if (priority < MINPRI)
132			priority = MINPRI;
133
134#if CONFIG_EMBEDDED
135		if ((thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON)  &&
136			(thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL)) {
137			thread->saved_importance = priority - thread->task_priority;
138			priority = MAXPRI_THROTTLE;
139		} else  {
140			thread->importance = priority - thread->task_priority;
141		}
142		/* No one can have a base priority less than MAXPRI_THROTTLE */
143		if (priority < MAXPRI_THROTTLE)
144			priority = MAXPRI_THROTTLE;
145#else	/* CONFIG_EMBEDDED */
146		thread->importance = priority - thread->task_priority;
147
148#endif /* CONFIG_EMBEDDED */
149
150		set_priority(thread, priority);
151	}
152
153	thread_unlock(thread);
154	splx(s);
155
156	return (KERN_SUCCESS);
157}
158
159/*
160 *	thread_set_policy
161 *
162 *	Set scheduling policy and parameters, both base and limit, for
163 *	the given thread. Policy can be any policy implemented by the
164 *	processor set, whether enabled or not.
165 */
166kern_return_t
167thread_set_policy(
168	thread_t				thread,
169	processor_set_t			pset,
170	policy_t				policy,
171	policy_base_t			base,
172	mach_msg_type_number_t	base_count,
173	policy_limit_t			limit,
174	mach_msg_type_number_t	limit_count)
175{
176	int 					max, bas;
177	kern_return_t			result = KERN_SUCCESS;
178
179	if (	thread == THREAD_NULL			||
180			pset == PROCESSOR_SET_NULL || pset != &pset0)
181		return (KERN_INVALID_ARGUMENT);
182
183	thread_mtx_lock(thread);
184
185	switch (policy) {
186
187	case POLICY_RR:
188	{
189		policy_rr_base_t		rr_base = (policy_rr_base_t) base;
190		policy_rr_limit_t		rr_limit = (policy_rr_limit_t) limit;
191
192		if (	base_count != POLICY_RR_BASE_COUNT		||
193				limit_count != POLICY_RR_LIMIT_COUNT		) {
194			result = KERN_INVALID_ARGUMENT;
195			break;
196		}
197
198		bas = rr_base->base_priority;
199		max = rr_limit->max_priority;
200		if (invalid_pri(bas) || invalid_pri(max)) {
201			result = KERN_INVALID_ARGUMENT;
202			break;
203		}
204
205		break;
206	}
207
208	case POLICY_FIFO:
209	{
210		policy_fifo_base_t		fifo_base = (policy_fifo_base_t) base;
211		policy_fifo_limit_t		fifo_limit = (policy_fifo_limit_t) limit;
212
213		if (	base_count != POLICY_FIFO_BASE_COUNT	||
214				limit_count != POLICY_FIFO_LIMIT_COUNT)		{
215			result = KERN_INVALID_ARGUMENT;
216			break;
217		}
218
219		bas = fifo_base->base_priority;
220		max = fifo_limit->max_priority;
221		if (invalid_pri(bas) || invalid_pri(max)) {
222			result = KERN_INVALID_ARGUMENT;
223			break;
224		}
225
226		break;
227	}
228
229	case POLICY_TIMESHARE:
230	{
231		policy_timeshare_base_t		ts_base = (policy_timeshare_base_t) base;
232		policy_timeshare_limit_t	ts_limit =
233						(policy_timeshare_limit_t) limit;
234
235		if (	base_count != POLICY_TIMESHARE_BASE_COUNT		||
236				limit_count != POLICY_TIMESHARE_LIMIT_COUNT			) {
237			result = KERN_INVALID_ARGUMENT;
238			break;
239		}
240
241		bas = ts_base->base_priority;
242		max = ts_limit->max_priority;
243		if (invalid_pri(bas) || invalid_pri(max)) {
244			result = KERN_INVALID_ARGUMENT;
245			break;
246		}
247
248		break;
249	}
250
251	default:
252		result = KERN_INVALID_POLICY;
253	}
254
255	if (result != KERN_SUCCESS) {
256		thread_mtx_unlock(thread);
257
258		return (result);
259	}
260
261	result = thread_policy_common(thread, policy, bas);
262
263	thread_mtx_unlock(thread);
264
265	return (result);
266}
267
268
269/*
270 * 	thread_policy
271 *
272 *	Set scheduling policy and parameters, both base and limit, for
273 *	the given thread. Policy must be a policy which is enabled for the
274 *	processor set. Change contained threads if requested.
275 */
276kern_return_t
277thread_policy(
278	thread_t				thread,
279	policy_t				policy,
280	policy_base_t			base,
281	mach_msg_type_number_t	count,
282	boolean_t				set_limit)
283{
284	kern_return_t			result = KERN_SUCCESS;
285	processor_set_t			pset = &pset0;
286	policy_limit_t			limit = NULL;
287	int						limcount = 0;
288	policy_rr_limit_data_t			rr_limit;
289	policy_fifo_limit_data_t		fifo_limit;
290	policy_timeshare_limit_data_t	ts_limit;
291
292	if (thread == THREAD_NULL)
293		return (KERN_INVALID_ARGUMENT);
294
295	thread_mtx_lock(thread);
296
297	if (	invalid_policy(policy)											||
298			((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0	) {
299		thread_mtx_unlock(thread);
300
301		return (KERN_INVALID_POLICY);
302	}
303
304	if (set_limit) {
305		/*
306	 	 * 	Set scheduling limits to base priority.
307		 */
308		switch (policy) {
309
310		case POLICY_RR:
311		{
312			policy_rr_base_t rr_base;
313
314			if (count != POLICY_RR_BASE_COUNT) {
315				result = KERN_INVALID_ARGUMENT;
316				break;
317			}
318
319			limcount = POLICY_RR_LIMIT_COUNT;
320			rr_base = (policy_rr_base_t) base;
321			rr_limit.max_priority = rr_base->base_priority;
322			limit = (policy_limit_t) &rr_limit;
323
324			break;
325		}
326
327		case POLICY_FIFO:
328		{
329			policy_fifo_base_t fifo_base;
330
331			if (count != POLICY_FIFO_BASE_COUNT) {
332				result = KERN_INVALID_ARGUMENT;
333				break;
334			}
335
336			limcount = POLICY_FIFO_LIMIT_COUNT;
337			fifo_base = (policy_fifo_base_t) base;
338			fifo_limit.max_priority = fifo_base->base_priority;
339			limit = (policy_limit_t) &fifo_limit;
340
341			break;
342		}
343
344		case POLICY_TIMESHARE:
345		{
346			policy_timeshare_base_t ts_base;
347
348			if (count != POLICY_TIMESHARE_BASE_COUNT) {
349				result = KERN_INVALID_ARGUMENT;
350				break;
351			}
352
353			limcount = POLICY_TIMESHARE_LIMIT_COUNT;
354			ts_base = (policy_timeshare_base_t) base;
355			ts_limit.max_priority = ts_base->base_priority;
356			limit = (policy_limit_t) &ts_limit;
357
358			break;
359		}
360
361		default:
362			result = KERN_INVALID_POLICY;
363			break;
364		}
365
366	}
367	else {
368		/*
369		 *	Use current scheduling limits. Ensure that the
370		 *	new base priority will not exceed current limits.
371		 */
372		switch (policy) {
373
374		case POLICY_RR:
375		{
376			policy_rr_base_t rr_base;
377
378			if (count != POLICY_RR_BASE_COUNT) {
379				result = KERN_INVALID_ARGUMENT;
380				break;
381			}
382
383			limcount = POLICY_RR_LIMIT_COUNT;
384			rr_base = (policy_rr_base_t) base;
385			if (rr_base->base_priority > thread->max_priority) {
386				result = KERN_POLICY_LIMIT;
387				break;
388			}
389
390			rr_limit.max_priority = thread->max_priority;
391			limit = (policy_limit_t) &rr_limit;
392
393			break;
394		}
395
396		case POLICY_FIFO:
397		{
398			policy_fifo_base_t fifo_base;
399
400			if (count != POLICY_FIFO_BASE_COUNT) {
401				result = KERN_INVALID_ARGUMENT;
402				break;
403			}
404
405			limcount = POLICY_FIFO_LIMIT_COUNT;
406			fifo_base = (policy_fifo_base_t) base;
407			if (fifo_base->base_priority > thread->max_priority) {
408				result = KERN_POLICY_LIMIT;
409				break;
410			}
411
412			fifo_limit.max_priority = thread->max_priority;
413			limit = (policy_limit_t) &fifo_limit;
414
415			break;
416		}
417
418		case POLICY_TIMESHARE:
419		{
420			policy_timeshare_base_t ts_base;
421
422			if (count != POLICY_TIMESHARE_BASE_COUNT) {
423				result = KERN_INVALID_ARGUMENT;
424				break;
425			}
426
427			limcount = POLICY_TIMESHARE_LIMIT_COUNT;
428			ts_base = (policy_timeshare_base_t) base;
429			if (ts_base->base_priority > thread->max_priority) {
430				result = KERN_POLICY_LIMIT;
431				break;
432			}
433
434			ts_limit.max_priority = thread->max_priority;
435			limit = (policy_limit_t) &ts_limit;
436
437			break;
438		}
439
440		default:
441			result = KERN_INVALID_POLICY;
442			break;
443		}
444
445	}
446
447	thread_mtx_unlock(thread);
448
449	if (result == KERN_SUCCESS)
450	    result = thread_set_policy(thread, pset,
451					 policy, base, count, limit, limcount);
452
453	return(result);
454}
455