1/*
2 * Copyright (c) 2000-2004 Apple Computer, 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#include <mach/mach_types.h>
30#include <mach/task_server.h>
31
32#include <kern/sched.h>
33#include <kern/task.h>
34
35static void
36task_priority(
37	task_t			task,
38	integer_t		priority,
39	integer_t		max_priority);
40
41kern_return_t
42task_policy_set(
43	task_t					task,
44	task_policy_flavor_t	flavor,
45	task_policy_t			policy_info,
46	mach_msg_type_number_t	count)
47{
48	kern_return_t		result = KERN_SUCCESS;
49
50	if (task == TASK_NULL || task == kernel_task)
51		return (KERN_INVALID_ARGUMENT);
52
53	switch (flavor) {
54
55	case TASK_CATEGORY_POLICY:
56	{
57		task_category_policy_t		info = (task_category_policy_t)policy_info;
58
59		if (count < TASK_CATEGORY_POLICY_COUNT)
60			return (KERN_INVALID_ARGUMENT);
61
62		task_lock(task);
63
64		if (	info->role == TASK_FOREGROUND_APPLICATION	||
65				info->role == TASK_BACKGROUND_APPLICATION		) {
66			switch (task->role) {
67
68			case TASK_FOREGROUND_APPLICATION:
69			case TASK_BACKGROUND_APPLICATION:
70			case TASK_UNSPECIFIED:
71				task_priority(task,
72								((info->role == TASK_FOREGROUND_APPLICATION)?
73									BASEPRI_FOREGROUND: BASEPRI_BACKGROUND),
74							  task->max_priority);
75				task->role = info->role;
76				break;
77
78			case TASK_CONTROL_APPLICATION:
79			case TASK_RENICED:
80				/* fail silently */
81				break;
82
83			default:
84				result = KERN_INVALID_ARGUMENT;
85				break;
86			}
87		}
88		else
89		if (info->role == TASK_CONTROL_APPLICATION) {
90			if (	task != current_task()			||
91					task->sec_token.val[0] != 0			)
92				result = KERN_INVALID_ARGUMENT;
93			else {
94				task_priority(task, BASEPRI_CONTROL, task->max_priority);
95				task->role = info->role;
96			}
97		}
98		else
99		if (info->role == TASK_GRAPHICS_SERVER) {
100			if (	task != current_task()			||
101					task->sec_token.val[0] != 0			)
102				result = KERN_INVALID_ARGUMENT;
103			else {
104				task_priority(task, MAXPRI_RESERVED - 3, MAXPRI_RESERVED);
105				task->role = info->role;
106			}
107		}
108		else
109			result = KERN_INVALID_ARGUMENT;
110
111		task_unlock(task);
112
113		break;
114	}
115
116	default:
117		result = KERN_INVALID_ARGUMENT;
118		break;
119	}
120
121	return (result);
122}
123
124static void
125task_priority(
126	task_t			task,
127	integer_t		priority,
128	integer_t		max_priority)
129{
130	thread_t		thread;
131
132	task->max_priority = max_priority;
133
134	if (priority > task->max_priority)
135		priority = task->max_priority;
136	else
137	if (priority < MINPRI)
138		priority = MINPRI;
139
140	task->priority = priority;
141
142	queue_iterate(&task->threads, thread, thread_t, task_threads) {
143		thread_mtx_lock(thread);
144
145		if (thread->active)
146			thread_task_priority(thread, priority, max_priority);
147
148		thread_mtx_unlock(thread);
149	}
150}
151
152kern_return_t
153task_importance(
154	task_t				task,
155	integer_t			importance)
156{
157	if (task == TASK_NULL || task == kernel_task)
158		return (KERN_INVALID_ARGUMENT);
159
160	task_lock(task);
161
162	if (!task->active) {
163		task_unlock(task);
164
165		return (KERN_TERMINATED);
166	}
167
168	if (task->role >= TASK_CONTROL_APPLICATION) {
169		task_unlock(task);
170
171		return (KERN_INVALID_ARGUMENT);
172	}
173
174	task_priority(task, importance + BASEPRI_DEFAULT, task->max_priority);
175	task->role = TASK_RENICED;
176
177	task_unlock(task);
178
179	return (KERN_SUCCESS);
180}
181
182kern_return_t
183task_policy_get(
184	task_t					task,
185	task_policy_flavor_t	flavor,
186	task_policy_t			policy_info,
187	mach_msg_type_number_t	*count,
188	boolean_t				*get_default)
189{
190	if (task == TASK_NULL || task == kernel_task)
191		return (KERN_INVALID_ARGUMENT);
192
193	switch (flavor) {
194
195	case TASK_CATEGORY_POLICY:
196	{
197		task_category_policy_t		info = (task_category_policy_t)policy_info;
198
199		if (*count < TASK_CATEGORY_POLICY_COUNT)
200			return (KERN_INVALID_ARGUMENT);
201
202		if (*get_default)
203			info->role = TASK_UNSPECIFIED;
204		else {
205			task_lock(task);
206			info->role = task->role;
207			task_unlock(task);
208		}
209		break;
210	}
211
212	default:
213		return (KERN_INVALID_ARGUMENT);
214	}
215
216	return (KERN_SUCCESS);
217}
218