Home
Reading
Searching
Subscribe
Sponsors
Statistics
Posting
Contact
Spam
Lists
Links
About
Hosting
Filtering
Features Download
Marketing
Archives
FAQ
Blog
 
Gmane
From: Trent Piepho <xyzzy <at> speakeasy.org>
Subject: race conditions in alsa core
Newsgroups: gmane.linux.alsa.devel
Date: Sunday 23rd September 2007 10:14:47 UTC (over 10 years ago)
In the process of trying to discover that kind of locking ALSA provides to
a
driver and what the driver must take care of itself, I think I have found
some
race conditions inside the alsa core.

I think there are likely quite a few, but this example was one of the
easiest
to prove.

ALSA uses unlocked_ioctl, which means ioctl calls aren't protected by the
BKL
and may run at the same time.

Some ioctls, for instance HW_PARAMS, don't appear to have any locking done
by
ALSA.  It's entirely possible for two hw_params calls to run at the same
time
on the same substream, and the ALSA core (and probably many drivers too)
can't
handle this.

The following patch helps to create a larger window for the race condition,
so
that it can be triggered consistently.

--- a/sound/core/pcm_native.c   Tue Sep 04 09:02:06 2007 +0000
+++ b/sound/core/pcm_native.c   Sat Sep 22 17:12:37 2007 -0700
@@ -411,6 +411,7 @@ static int snd_pcm_hw_params(struct snd_
 	runtime->channels = params_channels(params);
 	runtime->rate = params_rate(params);
 	runtime->period_size = params_period_size(params);
+	{ static unsigned long x=1; if(test_and_change_bit(0, &x)) msleep(10); }
 	runtime->periods = params_periods(params);
 	runtime->buffer_size = params_buffer_size(params);
 	runtime->tick_time = params_tick_time(params);

This causes every other call to snd_pcm_hw_params() to have a 10ms delay
between setting the period size and period count.  If there are two calls
within 10ms, the period count should come from the first call (which
slept),
while the period size will be from the second call.

My test program will call the HW_PARAMS ioctl twice from different threads
running at the same time.  The first call will ask for the maximum number
of
periods with minimum size, the second call for the minimum number of
periods
of maximum size.

When prepare is called, we discover that the runtime is set for the maximum
number of periods of maximum size, which exceeds the buffer size.  Of
course
even if it didn't exceed the buffer size, the params should be from one
call
or the other, not some random combination of both.

I've attaching a very simple dummy ALSA driver which shows this.  All it
does
is print timestamps and a few parameters when the various callback
functions
are invoked.  The output looks like this:

as_open - 0.084 us
as_hw_params - 552.864 us periods 128, period size 1024
as_hw_params - 589.996 us periods 1, period size 131072
as_prepare - 11065.307 us periods 128, period size 131072
as_close - 11278.229 us

Notice how in prepare the runtime has parameters that are a combination of
the
two hw_params calls.  This test program should trigger the same race with
any
other ALSA driver.  Just adjust the period count and size.

The test program doesn't use the ALSA lib.  It does need the headers from
the
alsa lib package to compile, since this seems to be the only place where
user
space headers for the device interface are provided.
 
CD: 4ms