Index: sys/dev/hwpmc/hwpmc_mod.c =================================================================== --- sys/dev/hwpmc/hwpmc_mod.c +++ sys/dev/hwpmc/hwpmc_mod.c @@ -142,8 +142,7 @@ /* various event handlers */ -static eventhandler_tag pmc_exit_tag, pmc_fork_tag, pmc_kld_load_tag, - pmc_kld_unload_tag; +static eventhandler_tag pmc_kld_load_tag, pmc_kld_unload_tag; /* Module statistics */ struct pmc_driverstats pmc_stats; @@ -239,9 +238,8 @@ static void pmc_maybe_remove_owner(struct pmc_owner *po); static void pmc_process_csw_in(struct thread *td); static void pmc_process_csw_out(struct thread *td); -static void pmc_process_exit(void *arg, struct proc *p); -static void pmc_process_fork(void *arg, struct proc *p1, - struct proc *p2, int n); +static void pmc_process_exit(struct proc *p); +static void pmc_process_fork(struct proc *p1, struct proc *p2); static void pmc_process_samples(int cpu, ring_type_t soft); static void pmc_release_pmc_descriptor(struct pmc *pmc); static void pmc_process_thread_add(struct thread *td); @@ -2091,10 +2089,13 @@ switch (function) { + case PMC_FN_PROCESS_EXIT: + pmc_process_exit(td->td_proc); + break; - /* - * Process exec() - */ + case PMC_FN_PROCESS_FORK: + pmc_process_fork(td->td_proc, (struct proc *)arg); + break; case PMC_FN_PROCESS_EXEC: { @@ -5057,7 +5058,7 @@ */ static void -pmc_process_exit(void *arg __unused, struct proc *p) +pmc_process_exit(struct proc *p) { struct pmc *pm; int adjri, cpu; @@ -5240,8 +5241,7 @@ */ static void -pmc_process_fork(void *arg __unused, struct proc *p1, struct proc *newproc, - int flags) +pmc_process_fork(struct proc *p1, struct proc *newproc) { int is_using_hwpmcs; unsigned int ri; @@ -5250,8 +5250,6 @@ struct pmc_owner *po; struct pmc_process *ppnew, *ppold; - (void) flags; /* unused parameter */ - PROC_LOCK(p1); is_using_hwpmcs = p1->p_flag & P_HWPMC; PROC_UNLOCK(p1); @@ -5720,12 +5718,6 @@ /* Initialize the task to prune the thread free list. */ TASK_INIT(&free_task, 0, pmc_thread_descriptor_pool_free_task, NULL); - /* register process {exit,fork,exec} handlers */ - pmc_exit_tag = EVENTHANDLER_REGISTER(process_exit, - pmc_process_exit, NULL, EVENTHANDLER_PRI_ANY); - pmc_fork_tag = EVENTHANDLER_REGISTER(process_fork, - pmc_process_fork, NULL, EVENTHANDLER_PRI_ANY); - /* register kld event handlers */ pmc_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, pmc_kld_load, NULL, EVENTHANDLER_PRI_ANY); @@ -5769,9 +5761,11 @@ struct pmc_ownerhash *ph; struct pmc_owner *po, *tmp; struct pmc_binding pb; + struct proc *p, *phead; #ifdef HWPMC_DEBUG struct pmc_processhash *prh; #endif + bool draining; PMCDBG0(MOD,INI,0, "cleanup"); @@ -5786,11 +5780,40 @@ return; } + /* + * Ensure that fork and exit hooks are not called. + * New forked processes are added at the head of allproc p_list. + * There is no need to drain processes before phead in allproc, + * they were forked after pmc_hook was cleared. + */ + sx_slock(&allproc_lock); pmc_hook = NULL; /* prevent new threads from entering module */ + phead = LIST_FIRST(&allproc); + for (;;) { + draining = false; + p = phead; + LIST_FOREACH_FROM(p, &allproc, p_list) { + PROC_LOCK(p); + if (p->p_state == PRS_NEW || + ((p->p_flag & P_WEXIT) != 0 && + p->p_state != PRS_ZOMBIE)) + draining = true; + PROC_UNLOCK(p); + if (draining) + break; + } + if (draining) { + sx_sunlock(&allproc_lock); + pause("hwpmcd", 1); + sx_slock(&allproc_lock); + } + else + break; + } + sx_sunlock(&allproc_lock); + /* deregister event handlers */ - EVENTHANDLER_DEREGISTER(process_fork, pmc_fork_tag); - EVENTHANDLER_DEREGISTER(process_exit, pmc_exit_tag); EVENTHANDLER_DEREGISTER(kld_load, pmc_kld_load_tag); EVENTHANDLER_DEREGISTER(kld_unload, pmc_kld_unload_tag); Index: sys/kern/kern_exit.c =================================================================== --- sys/kern/kern_exit.c +++ sys/kern/kern_exit.c @@ -39,6 +39,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_hwpmc_hooks.h" #include "opt_ktrace.h" #include @@ -73,6 +74,7 @@ #include #include #include +#include #include #include #ifdef KTRACE @@ -331,6 +333,10 @@ if (p->p_sysent->sv_onexit != NULL) p->p_sysent->sv_onexit(p); +#ifdef HWPMC_HOOKS + PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_PROCESS_EXIT, NULL); +#endif + /* * Check if any loadable modules need anything done at process exit. * E.g. SYSV IPC stuff. Index: sys/kern/kern_fork.c =================================================================== --- sys/kern/kern_fork.c +++ sys/kern/kern_fork.c @@ -39,6 +39,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_hwpmc_hooks.h" #include "opt_ktrace.h" #include "opt_kstack_pages.h" @@ -56,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -672,6 +674,10 @@ if (fr->fr_flags & RFPROCDESC) procdesc_new(p2, fr->fr_pd_flags); +#ifdef HWPMC_HOOKS + PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_PROCESS_FORK, p2); +#endif + /* * Both processes are set up, now check if any loadable modules want * to adjust anything. Index: sys/sys/pmckern.h =================================================================== --- sys/sys/pmckern.h +++ sys/sys/pmckern.h @@ -53,8 +53,8 @@ #define PMC_FN_CSW_IN 2 #define PMC_FN_CSW_OUT 3 #define PMC_FN_DO_SAMPLES 4 -#define PMC_FN_UNUSED1 5 -#define PMC_FN_UNUSED2 6 +#define PMC_FN_PROCESS_EXIT 5 +#define PMC_FN_PROCESS_FORK 6 #define PMC_FN_MMAP 7 #define PMC_FN_MUNMAP 8 #define PMC_FN_USER_CALLCHAIN 9