Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hwpmc/hwpmc_logging.c
Show First 20 Lines • Show All 229 Lines • ▼ Show 20 Lines | #endif | ||||
/* update stats */ | /* update stats */ | ||||
atomic_add_int(&pmc_stats.pm_buffer_requests, 1); | atomic_add_int(&pmc_stats.pm_buffer_requests, 1); | ||||
if (plb == NULL) | if (plb == NULL) | ||||
atomic_add_int(&pmc_stats.pm_buffer_requests_failed, 1); | atomic_add_int(&pmc_stats.pm_buffer_requests_failed, 1); | ||||
return (plb ? 0 : ENOMEM); | return (plb ? 0 : ENOMEM); | ||||
} | } | ||||
struct pmclog_proc_init_args { | |||||
struct proc *kthr; | |||||
struct pmc_owner *po; | |||||
bool exit; | |||||
bool acted; | |||||
}; | |||||
int | |||||
pmclog_proc_create(struct thread *td, void **handlep) | |||||
{ | |||||
struct pmclog_proc_init_args *ia; | |||||
int error; | |||||
ia = malloc(sizeof(*ia), M_TEMP, M_WAITOK | M_ZERO); | |||||
error = kproc_create(pmclog_loop, ia, &ia->kthr, | |||||
RFHIGHPID, 0, "hwpmc: proc(%d)", td->td_proc->p_pid); | |||||
if (error == 0) | |||||
*handlep = ia; | |||||
return (error); | |||||
} | |||||
void | |||||
pmclog_proc_ignite(void *handle, struct pmc_owner *po) | |||||
{ | |||||
struct pmclog_proc_init_args *ia; | |||||
ia = handle; | |||||
mtx_lock(&pmc_kthread_mtx); | |||||
MPASS(!ia->acted); | |||||
MPASS(ia->po == NULL); | |||||
MPASS(!ia->exit); | |||||
MPASS(ia->kthr != NULL); | |||||
if (po == NULL) { | |||||
ia->exit = true; | |||||
} else { | |||||
ia->po = po; | |||||
KASSERT(po->po_kthread == NULL, | |||||
("[pmclog,%d] po=%p kthread (%p) already present", | |||||
__LINE__, po, po->po_kthread)); | |||||
po->po_kthread = ia->kthr; | |||||
} | |||||
wakeup(ia); | |||||
while (!ia->acted) | |||||
msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogw", 0); | |||||
mtx_unlock(&pmc_kthread_mtx); | |||||
free(ia, M_TEMP); | |||||
} | |||||
/* | /* | ||||
* Log handler loop. | * Log handler loop. | ||||
* | * | ||||
* This function is executed by each pmc owner's helper thread. | * This function is executed by each pmc owner's helper thread. | ||||
*/ | */ | ||||
static void | static void | ||||
pmclog_loop(void *arg) | pmclog_loop(void *arg) | ||||
{ | { | ||||
int error; | struct pmclog_proc_init_args *ia; | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
struct pmclog_buffer *lb; | struct pmclog_buffer *lb; | ||||
struct proc *p; | struct proc *p; | ||||
struct ucred *ownercred; | struct ucred *ownercred; | ||||
struct ucred *mycred; | struct ucred *mycred; | ||||
struct thread *td; | struct thread *td; | ||||
sigset_t unb; | sigset_t unb; | ||||
struct uio auio; | struct uio auio; | ||||
struct iovec aiov; | struct iovec aiov; | ||||
size_t nbytes; | size_t nbytes; | ||||
int error; | |||||
po = (struct pmc_owner *) arg; | |||||
p = po->po_owner; | |||||
td = curthread; | td = curthread; | ||||
SIGEMPTYSET(unb); | SIGEMPTYSET(unb); | ||||
SIGADDSET(unb, SIGHUP); | SIGADDSET(unb, SIGHUP); | ||||
(void)kern_sigprocmask(td, SIG_UNBLOCK, &unb, NULL, 0); | (void)kern_sigprocmask(td, SIG_UNBLOCK, &unb, NULL, 0); | ||||
ia = arg; | |||||
MPASS(ia->kthr == curproc); | |||||
MPASS(!ia->acted); | |||||
mtx_lock(&pmc_kthread_mtx); | |||||
while (ia->po == NULL && !ia->exit) | |||||
msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogi", 0); | |||||
if (ia->exit) { | |||||
ia->acted = true; | |||||
wakeup(ia); | |||||
mtx_unlock(&pmc_kthread_mtx); | |||||
kproc_exit(0); | |||||
} | |||||
MPASS(ia->po != NULL); | |||||
po = ia->po; | |||||
ia->acted = true; | |||||
wakeup(ia); | |||||
mtx_unlock(&pmc_kthread_mtx); | |||||
ia = NULL; | |||||
p = po->po_owner; | |||||
mycred = td->td_ucred; | mycred = td->td_ucred; | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
ownercred = crhold(p->p_ucred); | ownercred = crhold(p->p_ucred); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
PMCDBG2(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); | PMCDBG2(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); | ||||
KASSERT(po->po_kthread == curthread->td_proc, | KASSERT(po->po_kthread == curthread->td_proc, | ||||
▲ Show 20 Lines • Show All 288 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Parameter 'logfd' is a file handle referencing an open file in the | * Parameter 'logfd' is a file handle referencing an open file in the | ||||
* owner process. This file needs to have been opened for writing. | * owner process. This file needs to have been opened for writing. | ||||
*/ | */ | ||||
int | int | ||||
pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) | pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) | ||||
{ | { | ||||
int error; | |||||
struct proc *p; | struct proc *p; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
/* | int error; | ||||
* As long as it is possible to get a LOR between pmc_sx lock and | |||||
* proctree/allproc sx locks used for adding a new process, assure | sx_assert(&pmc_sx, SA_XLOCKED); | ||||
* the former is not held here. | |||||
*/ | |||||
sx_assert(&pmc_sx, SA_UNLOCKED); | |||||
PMCDBG2(LOG,CFG,1, "config po=%p logfd=%d", po, logfd); | PMCDBG2(LOG,CFG,1, "config po=%p logfd=%d", po, logfd); | ||||
p = po->po_owner; | p = po->po_owner; | ||||
/* return EBUSY if a log file was already present */ | /* return EBUSY if a log file was already present */ | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
return (EBUSY); | return (EBUSY); | ||||
KASSERT(po->po_kthread == NULL, | |||||
("[pmclog,%d] po=%p kthread (%p) already present", __LINE__, po, | |||||
po->po_kthread)); | |||||
KASSERT(po->po_file == NULL, | KASSERT(po->po_file == NULL, | ||||
("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, | ("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, | ||||
po->po_file)); | po->po_file)); | ||||
/* get a reference to the file state */ | /* get a reference to the file state */ | ||||
error = fget_write(curthread, logfd, | error = fget_write(curthread, logfd, | ||||
cap_rights_init(&rights, CAP_WRITE), &po->po_file); | cap_rights_init(&rights, CAP_WRITE), &po->po_file); | ||||
if (error) | if (error) | ||||
goto error; | goto error; | ||||
/* mark process as owning a log file */ | /* mark process as owning a log file */ | ||||
po->po_flags |= PMC_PO_OWNS_LOGFILE; | po->po_flags |= PMC_PO_OWNS_LOGFILE; | ||||
error = kproc_create(pmclog_loop, po, &po->po_kthread, | |||||
RFHIGHPID, 0, "hwpmc: proc(%d)", p->p_pid); | |||||
if (error) | |||||
goto error; | |||||
/* mark process as using HWPMCs */ | /* mark process as using HWPMCs */ | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
p->p_flag |= P_HWPMC; | p->p_flag |= P_HWPMC; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
/* create a log initialization entry */ | /* create a log initialization entry */ | ||||
PMCLOG_RESERVE_WITH_ERROR(po, INITIALIZE, | PMCLOG_RESERVE_WITH_ERROR(po, INITIALIZE, | ||||
sizeof(struct pmclog_initialize)); | sizeof(struct pmclog_initialize)); | ||||
PMCLOG_EMIT32(PMC_VERSION); | PMCLOG_EMIT32(PMC_VERSION); | ||||
PMCLOG_EMIT32(md->pmd_cputype); | PMCLOG_EMIT32(md->pmd_cputype); | ||||
PMCLOG_DESPATCH(po); | PMCLOG_DESPATCH(po); | ||||
return (0); | return (0); | ||||
error: | error: | ||||
/* shutdown the thread */ | |||||
if (po->po_kthread) | |||||
pmclog_stop_kthread(po); | |||||
KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " | KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " | ||||
"stopped", __LINE__, po)); | "stopped", __LINE__, po)); | ||||
if (po->po_file) | if (po->po_file) | ||||
(void) fdrop(po->po_file, curthread); | (void) fdrop(po->po_file, curthread); | ||||
po->po_file = NULL; /* clear file and error state */ | po->po_file = NULL; /* clear file and error state */ | ||||
po->po_error = 0; | po->po_error = 0; | ||||
▲ Show 20 Lines • Show All 440 Lines • Show Last 20 Lines |