/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Bind all the threads of a process to a CPU. */ static int cpu_bind_process(proc_t *pp, processorid_t bind, processorid_t *obind, int *error) { kthread_t *tp; kthread_t *fp; int err = 0; int i; ASSERT(MUTEX_HELD(&pidlock)); /* skip kernel processes */ if (pp->p_flag & SSYS) { *obind = PBIND_NONE; *error = ENOTSUP; return (0); } mutex_enter(&pp->p_lock); tp = pp->p_tlist; if (tp != NULL) { fp = tp; do { i = cpu_bind_thread(tp, bind, obind, error); if (err == 0) err = i; } while ((tp = tp->t_forw) != fp); } mutex_exit(&pp->p_lock); return (err); } /* * Bind all the processes of a task to a CPU. */ static int cpu_bind_task(task_t *tk, processorid_t bind, processorid_t *obind, int *error) { proc_t *p; int err = 0; int i; ASSERT(MUTEX_HELD(&pidlock)); if ((p = tk->tk_memb_list) == NULL) return (ESRCH); do { if (!(p->p_flag & SSYS)) { i = cpu_bind_process(p, bind, obind, error); if (err == 0) err = i; } } while ((p = p->p_tasknext) != tk->tk_memb_list); return (err); } /* * Bind all the processes in a project to a CPU. */ static int cpu_bind_project(kproject_t *kpj, processorid_t bind, processorid_t *obind, int *error) { proc_t *p; int err = 0; int i; ASSERT(MUTEX_HELD(&pidlock)); for (p = practive; p != NULL; p = p->p_next) { if (p->p_tlist == NULL) continue; if (p->p_task->tk_proj == kpj && !(p->p_flag & SSYS)) { i = cpu_bind_process(p, bind, obind, error); if (err == 0) err = i; } } return (err); } /* * Bind all the processes in a zone to a CPU. */ int cpu_bind_zone(zone_t *zptr, processorid_t bind, processorid_t *obind, int *error) { proc_t *p; int err = 0; int i; ASSERT(MUTEX_HELD(&pidlock)); for (p = practive; p != NULL; p = p->p_next) { if (p->p_tlist == NULL) continue; if (p->p_zone == zptr && !(p->p_flag & SSYS)) { i = cpu_bind_process(p, bind, obind, error); if (err == 0) err = i; } } return (err); } /* * Bind all the processes in a process contract to a CPU. */ int cpu_bind_contract(cont_process_t *ctp, processorid_t bind, processorid_t *obind, int *error) { proc_t *p; int err = 0; int i; ASSERT(MUTEX_HELD(&pidlock)); for (p = practive; p != NULL; p = p->p_next) { if (p->p_tlist == NULL) continue; if (p->p_ct_process == ctp) { i = cpu_bind_process(p, bind, obind, error); if (err == 0) err = i; } } return (err); } /* * processor_bind(2) - Processor binding interfaces. */ int processor_bind(idtype_t idtype, id_t id, processorid_t bind, processorid_t *obindp) { processorid_t obind = PBIND_NONE; int ret = 0; int err = 0; cpu_t *cp; kthread_id_t tp; proc_t *pp; task_t *tk; kproject_t *kpj; zone_t *zptr; contract_t *ct; /* * Since we might be making a binding to a processor, hold the * cpu_lock so that the processor cannot be taken offline while * we do this. */ mutex_enter(&cpu_lock); /* * Check to be sure binding processor ID is valid. */ switch (bind) { default: if ((cp = cpu_get(bind)) == NULL || (cp->cpu_flags & (CPU_QUIESCED | CPU_OFFLINE))) ret = EINVAL; else if ((cp->cpu_flags & CPU_READY) == 0) ret = EIO; break; case PBIND_NONE: case PBIND_QUERY: case PBIND_HARD: case PBIND_SOFT: case PBIND_QUERY_TYPE: break; } if (ret) { mutex_exit(&cpu_lock); return (set_errno(ret)); } switch (idtype) { case P_LWPID: pp = curproc; mutex_enter(&pp->p_lock); if (id == P_MYID) { ret = cpu_bind_thread(curthread, bind, &obind, &err); } else { int found = 0; tp = pp->p_tlist; do { if (tp->t_tid == id) { ret = cpu_bind_thread(tp, bind, &obind, &err); found = 1; break; } } while ((tp = tp->t_forw) != pp->p_tlist); if (!found) ret = ESRCH; } mutex_exit(&pp->p_lock); break; case P_PID: /* * Note. Cannot use dotoprocs here because it doesn't find * system class processes, which are legal to query. */ mutex_enter(&pidlock); if (id == P_MYID) { ret = cpu_bind_process(curproc, bind, &obind, &err); } else if ((pp = prfind(id)) != NULL) { ret = cpu_bind_process(pp, bind, &obind, &err); } else { ret = ESRCH; } mutex_exit(&pidlock); break; case P_TASKID: mutex_enter(&pidlock); if (id == P_MYID) { proc_t *p = curproc; id = p->p_task->tk_tkid; } if ((tk = task_hold_by_id(id)) != NULL) { ret = cpu_bind_task(tk, bind, &obind, &err); mutex_exit(&pidlock); task_rele(tk); } else { mutex_exit(&pidlock); ret = ESRCH; } break; case P_PROJID: pp = curproc; if (id == P_MYID) id = curprojid(); if ((kpj = project_hold_by_id(id, pp->p_zone, PROJECT_HOLD_FIND)) == NULL) { ret = ESRCH; } else { mutex_enter(&pidlock); ret = cpu_bind_project(kpj, bind, &obind, &err); mutex_exit(&pidlock); project_rele(kpj); } break; case P_ZONEID: if (id == P_MYID) id = getzoneid(); if ((zptr = zone_find_by_id(id)) == NULL) { ret = ESRCH; } else { mutex_enter(&pidlock); ret = cpu_bind_zone(zptr, bind, &obind, &err); mutex_exit(&pidlock); zone_rele(zptr); } break; case P_CTID: if (id == P_MYID) id = PRCTID(curproc); if ((ct = contract_type_ptr(process_type, id, curproc->p_zone->zone_uniqid)) == NULL) { ret = ESRCH; } else { mutex_enter(&pidlock); ret = cpu_bind_contract(ct->ct_data, bind, &obind, &err); mutex_exit(&pidlock); contract_rele(ct); } break; case P_CPUID: if (id == P_MYID || bind != PBIND_NONE || cpu_get(id) == NULL) ret = EINVAL; else ret = cpu_unbind(id, B_TRUE); break; case P_ALL: if (id == P_MYID || bind != PBIND_NONE) { ret = EINVAL; } else { int i; cpu_t *cp = cpu_list; do { if ((cp->cpu_flags & CPU_EXISTS) == 0) continue; i = cpu_unbind(cp->cpu_id, B_TRUE); if (ret == 0) ret = i; } while ((cp = cp->cpu_next) != cpu_list); } break; default: /* * Spec says this is invalid, even though we could * handle other idtypes. */ ret = EINVAL; break; } mutex_exit(&cpu_lock); /* * If no search error occurred, see if any permissions errors did. */ if (ret == 0) ret = err; if (ret == 0 && obindp != NULL) if (copyout((caddr_t)&obind, (caddr_t)obindp, sizeof (obind)) == -1) ret = EFAULT; return (ret ? set_errno(ret) : 0); /* return success or failure */ }