FreeBSD/sys/dev/hwpmc/hwpmc_mod.c
/*
 * This function does the following things:
 *
 *  - detaches the PMC from hardware
 *  - unlinks all target threads that were attached to it
 *  - removes the PMC from its owner's list
 *  - destroys the PMC private mutex
 *
 * Once this function completes, the given pmc pointer can be freed by
 * calling pmc_destroy_pmc_descriptor().
 */
This function does the following things:
- detaches the PMC from hardware
- unlinks all target threads that were attached to it
- removes the PMC from its owner's list
- destroys the PMC private mutex

Once this function completes, the given pmc pointer can be freed by
calling pmc_destroy_pmc_descriptor().
This function does the following things : - detaches the PMC from hardware - unlinks all target threads that were attached to it - removes the PMC from its owner ' s list - destroys the PMC private mutex Once this function completes the given pmc pointer can be freed by calling pmc_destroy_pmc_descriptor () .
static void
pmc_release_pmc_descriptor(struct pmc *pm)
{
	enum pmc_mode mode;
	struct pmc_hw *phw;
	u_int adjri, ri, cpu;
	struct pmc_owner *po;
	struct pmc_binding pb;
	struct pmc_process *pp;
	struct pmc_classdep *pcd;
	struct pmc_target *ptgt, *tmp;
	sx_assert(&pmc_sx, SX_XLOCKED);
	KASSERT(pm, ("[pmc,%d] null pmc", __LINE__));
	ri   = PMC_TO_ROWINDEX(pm);
	pcd  = pmc_ri_to_classdep(md, ri, &adjri);
	mode = PMC_TO_MODE(pm);
	PMCDBG3(PMC,REL,1, "release-pmc pmc=%p ri=%d mode=%d", pm, ri,
	    mode);
	cpu = 0;
	if (PMC_IS_SYSTEM_MODE(mode)) {
		pmc_save_cpu_binding(&pb);
		cpu = PMC_TO_CPU(pm);
		pmc_select_cpu(cpu);
		CPU_CLR_ATOMIC(cpu, &pm->pm_cpustate);
		if (pm->pm_state == PMC_STATE_RUNNING &&
		    !CPU_ISSET(cpu, &pm->pm_stalled)) {
			phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
			KASSERT(phw->phw_pmc == pm,
			    ("[pmc, %d] pmc ptr ri(%d) hw(%p) pm(%p)",
				__LINE__, ri, phw->phw_pmc, pm));
			PMCDBG2(PMC,REL,2, "stopping cpu=%d ri=%d", cpu, ri);
			critical_enter();
			pcd->pcd_stop_pmc(cpu, adjri);
			critical_exit();
		}
		PMCDBG2(PMC,REL,2, "decfg cpu=%d ri=%d", cpu, ri);
		critical_enter();
		pcd->pcd_config_pmc(cpu, adjri, NULL);
		critical_exit();
		if (mode == PMC_MODE_SS && pm->pm_state == PMC_STATE_RUNNING) {
			po = pm->pm_owner;
			po->po_sscount--;
			if (po->po_sscount == 0) {
				atomic_subtract_rel_int(&pmc_ss_count, 1);
				LIST_REMOVE(po, po_ssnext);
			}
		}
		pm->pm_state = PMC_STATE_DELETED;
		pmc_restore_cpu_binding(&pb);
		pmc_wait_for_pmc_idle(pm);
	} else if (PMC_IS_VIRTUAL_MODE(mode)) {
		pm->pm_state = PMC_STATE_DELETED;
		pmc_wait_for_pmc_idle(pm);
		LIST_FOREACH_SAFE(ptgt, &pm->pm_targets, pt_next, tmp) {
			pp = ptgt->pt_process;
			pmc_unlink_target_process(pm, pp); 
			PMCDBG1(PMC,REL,3, "pp->refcnt=%d", pp->pp_refcnt);
			if (pp->pp_refcnt == 0) {
				pmc_remove_process_descriptor(pp);
				free(pp, M_PMC);
			}
		}
		cpu = curthread->td_oncpu; 
	}
	(void) pcd->pcd_release_pmc(cpu, adjri, pm);
	if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pm)))
		PMC_UNMARK_ROW_STANDALONE(ri);
	else
		PMC_UNMARK_ROW_THREAD(ri);
	if (pm->pm_owner) {
		LIST_REMOVE(pm, pm_next);
		pm->pm_owner = NULL;
	}
}
static void pmc_release_pmc_descriptor ( struct pmc * pm ) { enum pmc_mode mode ; struct pmc_hw * phw ; u_int adjri , ri , cpu ; struct pmc_owner * po ; struct pmc_binding pb ; struct pmc_process * pp ; struct pmc_classdep * pcd ; struct pmc_target * ptgt , * tmp ; sx_assert ( & pmc_sx , SX_XLOCKED ) ; KASSERT ( pm , ( " " , __LINE__ ) ) ; ri = PMC_TO_ROWINDEX ( pm ) ; pcd = pmc_ri_to_classdep ( md , ri , & adjri ) ; mode = PMC_TO_MODE ( pm ) ; PMCDBG3 ( PMC , REL , 1 , " " , pm , ri , mode ) ; cpu = 0 ; if ( PMC_IS_SYSTEM_MODE ( mode ) ) { pmc_save_cpu_binding ( & pb ) ; cpu = PMC_TO_CPU ( pm ) ; pmc_select_cpu ( cpu ) ; CPU_CLR_ATOMIC ( cpu , & pm -> pm_cpustate ) ; if ( pm -> pm_state == PMC_STATE_RUNNING && ! CPU_ISSET ( cpu , & pm -> pm_stalled ) ) { phw = pmc_pcpu [ cpu ] -> pc_hwpmcs [ ri ] ; KASSERT ( phw -> phw_pmc == pm , ( " " , __LINE__ , ri , phw -> phw_pmc , pm ) ) ; PMCDBG2 ( PMC , REL , 2 , " " , cpu , ri ) ; critical_enter ( ) ; pcd -> pcd_stop_pmc ( cpu , adjri ) ; critical_exit ( ) ; } PMCDBG2 ( PMC , REL , 2 , " " , cpu , ri ) ; critical_enter ( ) ; pcd -> pcd_config_pmc ( cpu , adjri , NULL ) ; critical_exit ( ) ; if ( mode == PMC_MODE_SS && pm -> pm_state == PMC_STATE_RUNNING ) { po = pm -> pm_owner ; po -> po_sscount -- ; if ( po -> po_sscount == 0 ) { atomic_subtract_rel_int ( & pmc_ss_count , 1 ) ; LIST_REMOVE ( po , po_ssnext ) ; } } pm -> pm_state = PMC_STATE_DELETED ; pmc_restore_cpu_binding ( & pb ) ; pmc_wait_for_pmc_idle ( pm ) ; } else if ( PMC_IS_VIRTUAL_MODE ( mode ) ) { pm -> pm_state = PMC_STATE_DELETED ; pmc_wait_for_pmc_idle ( pm ) ; LIST_FOREACH_SAFE ( ptgt , & pm -> pm_targets , pt_next , tmp ) { pp = ptgt -> pt_process ; pmc_unlink_target_process ( pm , pp ) ; PMCDBG1 ( PMC , REL , 3 , " " , pp -> pp_refcnt ) ; if ( pp -> pp_refcnt == 0 ) { pmc_remove_process_descriptor ( pp ) ; free ( pp , M_PMC ) ; } } cpu = curthread -> td_oncpu ; } ( void ) pcd -> pcd_release_pmc ( cpu , adjri , pm ) ; if ( PMC_IS_SYSTEM_MODE ( PMC_TO_MODE ( pm ) ) ) PMC_UNMARK_ROW_STANDALONE ( ri ) ; else PMC_UNMARK_ROW_THREAD ( ri ) ; if ( pm -> pm_owner ) { LIST_REMOVE ( pm , pm_next ) ; pm -> pm_owner = NULL ; } }
This function does the following things:
  - detaches the PMC from hardware
  - unlinks all target threads that were attached to it
  - removes the PMC from its owner's list
  - destroys the PMC private mutex
This function does the following things : - detaches the PMC from hardware - unlinks all target threads that were attached to it - removes the PMC from its owner ' s list - destroys the PMC private mutex
/*
	 * First, we take the PMC off hardware.
	 */ /*
		 * A system mode PMC runs on a specific CPU.  Switch
		 * to this CPU and turn hardware off.
		 */ /* switch off non-stalled CPUs */ /* adjust the global and process count of SS mode PMCs */ /*
		 * We could have references to this PMC structure in
		 * the per-cpu sample queues.  Wait for the queue to
		 * drain.
		 */ /*
		 * A virtual PMC could be running on multiple CPUs at
		 * a given instant.
		 *
		 * By marking its state as DELETED, we ensure that
		 * this PMC is never further scheduled on hardware.
		 *
		 * Then we wait till all CPUs are done with this PMC.
		 */ /* Wait for the PMCs runcount to come to zero. */ /*
		 * At this point the PMC is off all CPUs and cannot be
		 * freshly scheduled onto a CPU.  It is now safe to
		 * unlink all targets from this PMC.  If a
		 * process-record's refcount falls to zero, we remove
		 * it from the hash table.  The module-wide SX lock
		 * protects us from races.
		 */ /* frees 'ptgt' */ /*
			 * If the target process record shows that no
			 * PMCs are attached to it, reclaim its space.
			 */ /* setup cpu for pmd_release() */ /*
	 * Release any MD resources
	 */ /*
	 * Update row disposition
	 */ /* unlink from the owner's list */