Don't panic in hwpmc when stopping sampling.

When hwpmc stops sampling it will set the pm_state to something other
than PMC_STATE_RUNNING. This means the following sequence can happen:

CPU 0: Enter the interrupt handler
CPU 0: Set the thread TDP_CALLCHAIN pflag
CPU 1: Stop sampling
CPU 0: Call pmc_process_samples, sampling is stopped so clears ps_nsamples
CPU 0: Finishes interrupt processing with the TDP_CALLCHAIN flag set
CPU 0: Call pmc_capture_user_callchain to capture the user call chain
CPU 0: Find all the pmc sample are free so no call chains need to be captured
CPU 0: KASSERT because of this

This fixes the issue by checking if any of the samples have been stopped
and including this in te KASSERT.

PR:		204273
Reviewed by:	bz, gnn
Obtained from:	ABT Systems Ltd
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D6581
This commit is contained in:
Andrew Turner 2016-05-28 13:05:39 +00:00
parent c169d9fe07
commit 7bc7e3cd65
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=300902

View file

@ -4199,6 +4199,7 @@ pmc_capture_user_callchain(int cpu, int ring, struct trapframe *tf)
struct pmc_samplebuffer *psb;
#ifdef INVARIANTS
int ncallchains;
int nfree;
#endif
psb = pmc_pcpu[cpu]->pc_sb[ring];
@ -4210,6 +4211,7 @@ pmc_capture_user_callchain(int cpu, int ring, struct trapframe *tf)
#ifdef INVARIANTS
ncallchains = 0;
nfree = 0;
#endif
/*
@ -4221,6 +4223,10 @@ pmc_capture_user_callchain(int cpu, int ring, struct trapframe *tf)
ps = psb->ps_read;
ps_end = psb->ps_write;
do {
#ifdef INVARIANTS
if (ps->ps_pmc->pm_state != PMC_STATE_RUNNING)
nfree++;
#endif
if (ps->ps_nsamples != PMC_SAMPLE_INUSE)
goto next;
if (ps->ps_td != td)
@ -4256,7 +4262,7 @@ pmc_capture_user_callchain(int cpu, int ring, struct trapframe *tf)
ps = psb->ps_samples;
} while (ps != ps_end);
KASSERT(ncallchains > 0,
KASSERT(ncallchains > 0 || nfree > 0,
("[pmc,%d] cpu %d didn't find a sample to collect", __LINE__,
cpu));