Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hwpmc/hwpmc_mod.c
Show First 20 Lines • Show All 2,848 Lines • ▼ Show 20 Lines | |||||
#define PMC_DOWNGRADE_SX() do { \ | #define PMC_DOWNGRADE_SX() do { \ | ||||
sx_downgrade(&pmc_sx); \ | sx_downgrade(&pmc_sx); \ | ||||
is_sx_downgraded = 1; \ | is_sx_downgraded = 1; \ | ||||
} while (0) | } while (0) | ||||
static int | static int | ||||
pmc_syscall_handler(struct thread *td, void *syscall_args) | pmc_syscall_handler(struct thread *td, void *syscall_args) | ||||
{ | { | ||||
int error, is_sx_downgraded, is_sx_locked, op; | int error, is_sx_downgraded, op; | ||||
struct pmc_syscall_args *c; | struct pmc_syscall_args *c; | ||||
void *pmclog_proc_handle; | |||||
void *arg; | void *arg; | ||||
PMC_GET_SX_XLOCK(ENOSYS); | |||||
is_sx_downgraded = 0; | |||||
is_sx_locked = 1; | |||||
c = (struct pmc_syscall_args *) syscall_args; | c = (struct pmc_syscall_args *)syscall_args; | ||||
op = c->pmop_code; | op = c->pmop_code; | ||||
arg = c->pmop_data; | arg = c->pmop_data; | ||||
if (op == PMC_OP_CONFIGURELOG) { | |||||
/* | |||||
* We cannot create the logging process inside | |||||
* pmclog_configure_log() because there is a LOR | |||||
* between pmc_sx and process structure locks. | |||||
* Instead, pre-create the process and ignite the loop | |||||
* if everything is fine, otherwise direct the process | |||||
* to exit. | |||||
*/ | |||||
error = pmclog_proc_create(td, &pmclog_proc_handle); | |||||
if (error != 0) | |||||
goto done_syscall; | |||||
} | |||||
PMC_GET_SX_XLOCK(ENOSYS); | |||||
is_sx_downgraded = 0; | |||||
PMCDBG3(MOD,PMS,1, "syscall op=%d \"%s\" arg=%p", op, | PMCDBG3(MOD,PMS,1, "syscall op=%d \"%s\" arg=%p", op, | ||||
pmc_op_to_name[op], arg); | pmc_op_to_name[op], arg); | ||||
error = 0; | error = 0; | ||||
atomic_add_int(&pmc_stats.pm_syscalls, 1); | atomic_add_int(&pmc_stats.pm_syscalls, 1); | ||||
switch (op) { | switch (op) { | ||||
/* | /* | ||||
* Configure a log file. | * Configure a log file. | ||||
* | * | ||||
* XXX This OP will be reworked. | * XXX This OP will be reworked. | ||||
*/ | */ | ||||
case PMC_OP_CONFIGURELOG: | case PMC_OP_CONFIGURELOG: | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
struct pmc_op_configurelog cl; | struct pmc_op_configurelog cl; | ||||
sx_assert(&pmc_sx, SX_XLOCKED); | if ((error = copyin(arg, &cl, sizeof(cl))) != 0) { | ||||
pmclog_proc_ignite(pmclog_proc_handle, NULL); | |||||
if ((error = copyin(arg, &cl, sizeof(cl))) != 0) | |||||
break; | break; | ||||
} | |||||
/* mark this process as owning a log file */ | /* mark this process as owning a log file */ | ||||
p = td->td_proc; | p = td->td_proc; | ||||
if ((po = pmc_find_owner_descriptor(p)) == NULL) | if ((po = pmc_find_owner_descriptor(p)) == NULL) | ||||
if ((po = pmc_allocate_owner_descriptor(p)) == NULL) { | if ((po = pmc_allocate_owner_descriptor(p)) == NULL) { | ||||
pmclog_proc_ignite(pmclog_proc_handle, NULL); | |||||
error = ENOMEM; | error = ENOMEM; | ||||
break; | break; | ||||
} | } | ||||
/* | /* | ||||
* If a valid fd was passed in, try to configure that, | * If a valid fd was passed in, try to configure that, | ||||
* otherwise if 'fd' was less than zero and there was | * otherwise if 'fd' was less than zero and there was | ||||
* a log file configured, flush its buffers and | * a log file configured, flush its buffers and | ||||
* de-configure it. | * de-configure it. | ||||
*/ | */ | ||||
if (cl.pm_logfd >= 0) { | if (cl.pm_logfd >= 0) { | ||||
sx_xunlock(&pmc_sx); | |||||
is_sx_locked = 0; | |||||
error = pmclog_configure_log(md, po, cl.pm_logfd); | error = pmclog_configure_log(md, po, cl.pm_logfd); | ||||
pmclog_proc_ignite(pmclog_proc_handle, error == 0 ? | |||||
po : NULL); | |||||
} else if (po->po_flags & PMC_PO_OWNS_LOGFILE) { | } else if (po->po_flags & PMC_PO_OWNS_LOGFILE) { | ||||
pmclog_proc_ignite(pmclog_proc_handle, NULL); | |||||
pmclog_process_closelog(po); | pmclog_process_closelog(po); | ||||
error = pmclog_close(po); | error = pmclog_close(po); | ||||
if (error == 0) { | if (error == 0) { | ||||
LIST_FOREACH(pm, &po->po_pmcs, pm_next) | LIST_FOREACH(pm, &po->po_pmcs, pm_next) | ||||
if (pm->pm_flags & PMC_F_NEEDS_LOGFILE && | if (pm->pm_flags & PMC_F_NEEDS_LOGFILE && | ||||
pm->pm_state == PMC_STATE_RUNNING) | pm->pm_state == PMC_STATE_RUNNING) | ||||
pmc_stop(pm); | pmc_stop(pm); | ||||
error = pmclog_deconfigure_log(po); | error = pmclog_deconfigure_log(po); | ||||
} | } | ||||
} else | } else { | ||||
pmclog_proc_ignite(pmclog_proc_handle, NULL); | |||||
error = EINVAL; | error = EINVAL; | ||||
if (error) | |||||
break; | |||||
} | } | ||||
} | |||||
break; | break; | ||||
/* | /* | ||||
* Flush a log file. | * Flush a log file. | ||||
*/ | */ | ||||
case PMC_OP_FLUSHLOG: | case PMC_OP_FLUSHLOG: | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 1,077 Lines • ▼ Show 20 Lines | #endif | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (is_sx_locked != 0) { | |||||
if (is_sx_downgraded) | if (is_sx_downgraded) | ||||
sx_sunlock(&pmc_sx); | sx_sunlock(&pmc_sx); | ||||
else | else | ||||
sx_xunlock(&pmc_sx); | sx_xunlock(&pmc_sx); | ||||
} | done_syscall: | ||||
if (error) | if (error) | ||||
atomic_add_int(&pmc_stats.pm_syscall_errors, 1); | atomic_add_int(&pmc_stats.pm_syscall_errors, 1); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Helper functions | * Helper functions | ||||
▲ Show 20 Lines • Show All 1,176 Lines • Show Last 20 Lines |