[PATCH] ARM: perf: remove erroneous check on active_events
Russell King - ARM Linux
linux at arm.linux.org.uk
Thu Apr 28 11:41:08 EDT 2011
On Wed, Apr 27, 2011 at 10:57:16AM +0100, Mark Rutland wrote:
> diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
> index fd6403c..29a0cf8 100644
> --- a/arch/arm/kernel/perf_event.c
> +++ b/arch/arm/kernel/perf_event.c
> @@ -560,11 +560,6 @@ static int armpmu_event_init(struct perf_event *event)
> event->destroy = hw_perf_event_destroy;
>
> if (!atomic_inc_not_zero(&active_events)) {
> - if (atomic_read(&active_events) > armpmu->num_events) {
> - atomic_dec(&active_events);
Yuck. This is a good example of atomic_* abuse. The above does nothing
to deal with the situation where two threads are running thusly:
CPU0 CPU1
atomic_inc_not_zero(&active_events)
atomic_inc_not_zero(&active_events)
atomic_read(&active_events)
atomic_read(&active_events)
atomic_dec(&active_events)
atomic_dec(&active_events)
return -ENOSPC
return -ENOSPC
when one of those two should have succeeded. I do wish people would
get out of the habbit of using atomic variables - they seem to be ripe
for this kind of abuse.
The only time that atomic variables are atomic is for each individual
_operation_ on the type, not across several operations, and certainly
not atomic_read() or atomic_set().
What it really wants to be is a spinlock or mutex so that it can do
something like this:
int err = 0;
mutex_lock(&active_events_lock);
if (++active_events > armpmu->num_events) {
active_events--;
err = -ENOSPC;
}
mutex_unlock(&active_events);
if (err)
return err;
which gives well defined semantics, and ensures that when two CPUs are
racing, one will at least succeed.
More information about the linux-arm-kernel
mailing list