Merge illumos-gate
[unleashed.git] / kernel / syscall / processor_bind.c
blob034afd05c621304fc8e13a03e3e7a0e776b3b7b0
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/var.h>
29 #include <sys/thread.h>
30 #include <sys/cpuvar.h>
31 #include <sys/kstat.h>
32 #include <sys/uadmin.h>
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/cmn_err.h>
36 #include <sys/procset.h>
37 #include <sys/processor.h>
38 #include <sys/debug.h>
39 #include <sys/task.h>
40 #include <sys/project.h>
41 #include <sys/zone.h>
42 #include <sys/contract_impl.h>
43 #include <sys/contract/process_impl.h>
46 * Bind all the threads of a process to a CPU.
48 static int
49 cpu_bind_process(proc_t *pp, processorid_t bind, processorid_t *obind,
50 int *error)
52 kthread_t *tp;
53 kthread_t *fp;
54 int err = 0;
55 int i;
57 ASSERT(MUTEX_HELD(&pidlock));
59 /* skip kernel processes */
60 if (pp->p_flag & SSYS) {
61 *obind = PBIND_NONE;
62 *error = ENOTSUP;
63 return (0);
66 mutex_enter(&pp->p_lock);
67 tp = pp->p_tlist;
68 if (tp != NULL) {
69 fp = tp;
70 do {
71 i = cpu_bind_thread(tp, bind, obind, error);
72 if (err == 0)
73 err = i;
74 } while ((tp = tp->t_forw) != fp);
77 mutex_exit(&pp->p_lock);
78 return (err);
82 * Bind all the processes of a task to a CPU.
84 static int
85 cpu_bind_task(task_t *tk, processorid_t bind, processorid_t *obind,
86 int *error)
88 proc_t *p;
89 int err = 0;
90 int i;
92 ASSERT(MUTEX_HELD(&pidlock));
94 if ((p = tk->tk_memb_list) == NULL)
95 return (ESRCH);
97 do {
98 if (!(p->p_flag & SSYS)) {
99 i = cpu_bind_process(p, bind, obind, error);
100 if (err == 0)
101 err = i;
103 } while ((p = p->p_tasknext) != tk->tk_memb_list);
105 return (err);
109 * Bind all the processes in a project to a CPU.
111 static int
112 cpu_bind_project(kproject_t *kpj, processorid_t bind, processorid_t *obind,
113 int *error)
115 proc_t *p;
116 int err = 0;
117 int i;
119 ASSERT(MUTEX_HELD(&pidlock));
121 for (p = practive; p != NULL; p = p->p_next) {
122 if (p->p_tlist == NULL)
123 continue;
124 if (p->p_task->tk_proj == kpj && !(p->p_flag & SSYS)) {
125 i = cpu_bind_process(p, bind, obind, error);
126 if (err == 0)
127 err = i;
130 return (err);
134 * Bind all the processes in a zone to a CPU.
137 cpu_bind_zone(zone_t *zptr, processorid_t bind, processorid_t *obind,
138 int *error)
140 proc_t *p;
141 int err = 0;
142 int i;
144 ASSERT(MUTEX_HELD(&pidlock));
146 for (p = practive; p != NULL; p = p->p_next) {
147 if (p->p_tlist == NULL)
148 continue;
149 if (p->p_zone == zptr && !(p->p_flag & SSYS)) {
150 i = cpu_bind_process(p, bind, obind, error);
151 if (err == 0)
152 err = i;
155 return (err);
159 * Bind all the processes in a process contract to a CPU.
162 cpu_bind_contract(cont_process_t *ctp, processorid_t bind, processorid_t *obind,
163 int *error)
165 proc_t *p;
166 int err = 0;
167 int i;
169 ASSERT(MUTEX_HELD(&pidlock));
171 for (p = practive; p != NULL; p = p->p_next) {
172 if (p->p_tlist == NULL)
173 continue;
174 if (p->p_ct_process == ctp) {
175 i = cpu_bind_process(p, bind, obind, error);
176 if (err == 0)
177 err = i;
180 return (err);
184 * processor_bind(2) - Processor binding interfaces.
187 processor_bind(idtype_t idtype, id_t id, processorid_t bind,
188 processorid_t *obindp)
190 processorid_t obind = PBIND_NONE;
191 int ret = 0;
192 int err = 0;
193 cpu_t *cp;
194 kthread_id_t tp;
195 proc_t *pp;
196 task_t *tk;
197 kproject_t *kpj;
198 zone_t *zptr;
199 contract_t *ct;
202 * Since we might be making a binding to a processor, hold the
203 * cpu_lock so that the processor cannot be taken offline while
204 * we do this.
206 mutex_enter(&cpu_lock);
209 * Check to be sure binding processor ID is valid.
211 switch (bind) {
212 default:
213 if ((cp = cpu_get(bind)) == NULL ||
214 (cp->cpu_flags & (CPU_QUIESCED | CPU_OFFLINE)))
215 ret = EINVAL;
216 else if ((cp->cpu_flags & CPU_READY) == 0)
217 ret = EIO;
218 break;
220 case PBIND_NONE:
221 case PBIND_QUERY:
222 case PBIND_HARD:
223 case PBIND_SOFT:
224 case PBIND_QUERY_TYPE:
225 break;
228 if (ret) {
229 mutex_exit(&cpu_lock);
230 return (set_errno(ret));
233 switch (idtype) {
234 case P_LWPID:
235 pp = curproc;
236 mutex_enter(&pp->p_lock);
237 if (id == P_MYID) {
238 ret = cpu_bind_thread(curthread, bind, &obind, &err);
239 } else {
240 int found = 0;
242 tp = pp->p_tlist;
243 do {
244 if (tp->t_tid == id) {
245 ret = cpu_bind_thread(tp,
246 bind, &obind, &err);
247 found = 1;
248 break;
250 } while ((tp = tp->t_forw) != pp->p_tlist);
251 if (!found)
252 ret = ESRCH;
254 mutex_exit(&pp->p_lock);
255 break;
257 case P_PID:
259 * Note. Cannot use dotoprocs here because it doesn't find
260 * system class processes, which are legal to query.
262 mutex_enter(&pidlock);
263 if (id == P_MYID) {
264 ret = cpu_bind_process(curproc, bind, &obind, &err);
265 } else if ((pp = prfind(id)) != NULL) {
266 ret = cpu_bind_process(pp, bind, &obind, &err);
267 } else {
268 ret = ESRCH;
270 mutex_exit(&pidlock);
271 break;
273 case P_TASKID:
274 mutex_enter(&pidlock);
275 if (id == P_MYID) {
276 proc_t *p = curproc;
277 id = p->p_task->tk_tkid;
280 if ((tk = task_hold_by_id(id)) != NULL) {
281 ret = cpu_bind_task(tk, bind, &obind, &err);
282 mutex_exit(&pidlock);
283 task_rele(tk);
284 } else {
285 mutex_exit(&pidlock);
286 ret = ESRCH;
288 break;
290 case P_PROJID:
291 pp = curproc;
292 if (id == P_MYID)
293 id = curprojid();
294 if ((kpj = project_hold_by_id(id, pp->p_zone,
295 PROJECT_HOLD_FIND)) == NULL) {
296 ret = ESRCH;
297 } else {
298 mutex_enter(&pidlock);
299 ret = cpu_bind_project(kpj, bind, &obind, &err);
300 mutex_exit(&pidlock);
301 project_rele(kpj);
303 break;
305 case P_ZONEID:
306 if (id == P_MYID)
307 id = getzoneid();
309 if ((zptr = zone_find_by_id(id)) == NULL) {
310 ret = ESRCH;
311 } else {
312 mutex_enter(&pidlock);
313 ret = cpu_bind_zone(zptr, bind, &obind, &err);
314 mutex_exit(&pidlock);
315 zone_rele(zptr);
317 break;
319 case P_CTID:
320 if (id == P_MYID)
321 id = PRCTID(curproc);
323 if ((ct = contract_type_ptr(process_type, id,
324 curproc->p_zone->zone_uniqid)) == NULL) {
325 ret = ESRCH;
326 } else {
327 mutex_enter(&pidlock);
328 ret = cpu_bind_contract(ct->ct_data,
329 bind, &obind, &err);
330 mutex_exit(&pidlock);
331 contract_rele(ct);
333 break;
335 case P_CPUID:
336 if (id == P_MYID || bind != PBIND_NONE || cpu_get(id) == NULL)
337 ret = EINVAL;
338 else
339 ret = cpu_unbind(id, B_TRUE);
340 break;
342 case P_ALL:
343 if (id == P_MYID || bind != PBIND_NONE) {
344 ret = EINVAL;
345 } else {
346 int i;
347 cpu_t *cp = cpu_list;
348 do {
349 if ((cp->cpu_flags & CPU_EXISTS) == 0)
350 continue;
351 i = cpu_unbind(cp->cpu_id, B_TRUE);
352 if (ret == 0)
353 ret = i;
354 } while ((cp = cp->cpu_next) != cpu_list);
356 break;
358 default:
360 * Spec says this is invalid, even though we could
361 * handle other idtypes.
363 ret = EINVAL;
364 break;
366 mutex_exit(&cpu_lock);
369 * If no search error occurred, see if any permissions errors did.
371 if (ret == 0)
372 ret = err;
374 if (ret == 0 && obindp != NULL)
375 if (copyout((caddr_t)&obind, (caddr_t)obindp,
376 sizeof (obind)) == -1)
377 ret = EFAULT;
378 return (ret ? set_errno(ret) : 0); /* return success or failure */