diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -3280,6 +3280,103 @@ is_sx_downgraded = 1; \ } while (0) +/* + * Main body of PMC_OP_PMCATTACH. + */ +static int +pmc_do_op_pmcattach(struct thread *td, struct pmc_op_pmcattach a) +{ + struct pmc *pm; + struct proc *p; + int error; + + sx_assert(&pmc_sx, SX_XLOCKED); + + if (a.pm_pid < 0) { + return (EINVAL); + } else if (a.pm_pid == 0) { + a.pm_pid = td->td_proc->p_pid; + } + + error = pmc_find_pmc(a.pm_pmc, &pm); + if (error != 0) + return (error); + + if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pm))) + return (EINVAL); + + /* PMCs may be (re)attached only when allocated or stopped */ + if (pm->pm_state == PMC_STATE_RUNNING) { + return (EBUSY); + } else if (pm->pm_state != PMC_STATE_ALLOCATED && + pm->pm_state != PMC_STATE_STOPPED) { + return (EINVAL); + } + + /* lookup pid */ + if ((p = pfind(a.pm_pid)) == NULL) + return (ESRCH); + + /* + * Ignore processes that are working on exiting. + */ + if ((p->p_flag & P_WEXIT) != 0) { + PROC_UNLOCK(p); /* pfind() returns a locked process */ + return (ESRCH); + } + + /* + * We are allowed to attach a PMC to a process if we can debug it. + */ + error = p_candebug(curthread, p); + + PROC_UNLOCK(p); + + if (error == 0) + error = pmc_attach_process(p, pm); + + return (error); +} + +/* + * Main body of PMC_OP_PMCDETACH. + */ +static int +pmc_do_op_pmcdetach(struct thread *td, struct pmc_op_pmcattach a) +{ + struct pmc *pm; + struct proc *p; + int error; + + if (a.pm_pid < 0) { + return (EINVAL); + } else if (a.pm_pid == 0) + a.pm_pid = td->td_proc->p_pid; + + error = pmc_find_pmc(a.pm_pmc, &pm); + if (error != 0) + return (error); + + if ((p = pfind(a.pm_pid)) == NULL) + return (ESRCH); + + /* + * Treat processes that are in the process of exiting as if they were + * not present. + */ + if ((p->p_flag & P_WEXIT) != 0) { + PROC_UNLOCK(p); + return (ESRCH); + } + + PROC_UNLOCK(p); /* pfind() returns a locked process */ + + if (error == 0) + error = pmc_detach_process(p, pm); + + return (error); +} + static int pmc_syscall_handler(struct thread *td, void *syscall_args) { @@ -3996,114 +4093,33 @@ } break; - /* * Attach a PMC to a process. */ - case PMC_OP_PMCATTACH: { - struct pmc *pm; - struct proc *p; struct pmc_op_pmcattach a; - sx_assert(&pmc_sx, SX_XLOCKED); - - if ((error = copyin(arg, &a, sizeof(a))) != 0) - break; - - if (a.pm_pid < 0) { - error = EINVAL; - break; - } else if (a.pm_pid == 0) - a.pm_pid = td->td_proc->p_pid; - - if ((error = pmc_find_pmc(a.pm_pmc, &pm)) != 0) - break; - - if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pm))) { - error = EINVAL; - break; - } - - /* PMCs may be (re)attached only when allocated or stopped */ - if (pm->pm_state == PMC_STATE_RUNNING) { - error = EBUSY; - break; - } else if (pm->pm_state != PMC_STATE_ALLOCATED && - pm->pm_state != PMC_STATE_STOPPED) { - error = EINVAL; - break; - } - - /* lookup pid */ - if ((p = pfind(a.pm_pid)) == NULL) { - error = ESRCH; - break; - } - - /* - * Ignore processes that are working on exiting. - */ - if (p->p_flag & P_WEXIT) { - error = ESRCH; - PROC_UNLOCK(p); /* pfind() returns a locked process */ + error = copyin(arg, &a, sizeof(a)); + if (error != 0) break; - } - /* - * we are allowed to attach a PMC to a process if - * we can debug it. - */ - error = p_candebug(curthread, p); - - PROC_UNLOCK(p); - - if (error == 0) - error = pmc_attach_process(p, pm); + error = pmc_do_op_pmcattach(td, a); } break; - /* * Detach an attached PMC from a process. */ - case PMC_OP_PMCDETACH: { - struct pmc *pm; - struct proc *p; struct pmc_op_pmcattach a; - if ((error = copyin(arg, &a, sizeof(a))) != 0) - break; - - if (a.pm_pid < 0) { - error = EINVAL; - break; - } else if (a.pm_pid == 0) - a.pm_pid = td->td_proc->p_pid; - - if ((error = pmc_find_pmc(a.pm_pmc, &pm)) != 0) - break; - - if ((p = pfind(a.pm_pid)) == NULL) { - error = ESRCH; + error = copyin(arg, &a, sizeof(a)); + if (error != 0) break; - } - /* - * Treat processes that are in the process of exiting - * as if they were not present. - */ - - if (p->p_flag & P_WEXIT) - error = ESRCH; - - PROC_UNLOCK(p); /* pfind() returns a locked process */ - - if (error == 0) - error = pmc_detach_process(p, pm); + error = pmc_do_op_pmcdetach(td, a); } break;