All of lore.kernel.org
 help / color / mirror / Atom feed
* Races in alsa-lib with threads
@ 2012-11-10  2:03 Trent Piepho
  2012-11-10 13:53 ` Takashi Iwai
  0 siblings, 1 reply; 32+ messages in thread
From: Trent Piepho @ 2012-11-10  2:03 UTC (permalink / raw)
  To: alsa-devel

We've found a race with alsa-lib functions are called from multiple
threads.  I was under the impression that alsa-lib was supposed to be
thread safe.  Is this not the case and all alsa calls should be done
one from thread or protected by a mutex?

The race we found was in sync_ptr1() in pcm_hw.c.  This issues the
ioctl() to get the current hw ptr from the kernel and send the app ptr
to the kernel.  The communication is done by passing a pointer to
hw->sync_ptr, a field in the snd_pcm_hw_t structure for the pcm.  Any
thread calling sync_ptr1 will pass the same structure to the kernel.
This should be a red flag for a race, having two threads write to the
same data structure at the same time.

This function gets called by snd_pcm_writei(), as part of that
function getting the current hw pointer so it can calculate the avail
value.  And again when it actually writes data to commit the new app
pointer to the kernel.

It also gets called by snd_pcm_delay() if a rate plugin is used.
snd_pcm_rate_delay() will end up calling snd_pcm_hw_hwsync() and that
does a sync_ptr1() call.

So imaging two threads, one writing data and calling snd_pcm_writei()
and another calling snd_pcm_delay() as part of trying to sync audio
playback.  gstreamer does this!

The ioctl is handled by snd_pcm_sync_ptr() in pcm_native.c.  It gets
the stream lock while it reads/writes the various fields a sync struct
on the stack, then releases the lock and calls copy_to_user to write
the sync struct from its stack to userspace.

Here's how the race works.
Thread 1 calls snd_pcm_delay().
  sync_ptr1 is called
  snd_pcm_sync_ptr gets the lock, fills a struct with the current
data, releases the lock.  Does not call copy_to_user yet!
  Thread 2 runs!  It calls snd_pcm_writei(), actually writes data too
    It calls sync_ptr1() to update the app pointer with the new data and returns
    The snd_pcm_writei() call returns
  Thread 1 runs again, calls copy_to_user
    The copy_to_user writes the OLD struct that was prepared back on
the 3rd line into userspace
    The hw and app pointer values, as far as the userspace copy in
alsa-lib is concerned, have regressed to what they were before the
call to snd_pcm_writei()!

You get an audio stutter as the data written is overwritten by the
next write.  The race turns out to not be that unlikely.  The stream
lock is held and then released before calling copy_to_user.  When it's
released irqs are enabled.  If a period has elapsed while the lock was
held, the irq handle runs now, the elapsing period will wake anything
blocked in poll() waiting for space, which then probably gets to run
immediately since the schedule likes tasks that have been sleeping and
just woke, and the new task was probably blocked waiting to write data
so that's what it does as soon as it runs.

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2012-11-15 13:05 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-10  2:03 Races in alsa-lib with threads Trent Piepho
2012-11-10 13:53 ` Takashi Iwai
2012-11-11 16:35   ` Jaroslav Kysela
2012-11-12 19:40     ` Rob Krakora
2012-11-13  6:32       ` Takashi Iwai
2012-11-13  7:14         ` Trent Piepho
2012-11-13  7:30           ` Takashi Iwai
     [not found]             ` <5175C6FEA820754B902FF6873E9285B00C985240@039-SN2MPN1-021.039d.mgd.msft.net>
2012-11-13 13:47               ` Krakora Robert-B42341
2012-11-13 13:50               ` Takashi Iwai
2012-11-13 14:04                 ` Krakora Robert-B42341
2012-11-13 14:18                   ` Takashi Iwai
2012-11-13 14:08                 ` Jaroslav Kysela
2012-11-13 14:15                   ` Krakora Robert-B42341
2012-11-13 14:19                   ` Takashi Iwai
2012-11-13 14:26                 ` Krakora Robert-B42341
2012-11-13 19:41                 ` Trent Piepho
2012-11-13 20:23                   ` Clemens Ladisch
2012-11-13 20:36                     ` Trent Piepho
2012-11-13 20:29                   ` Takashi Iwai
2012-11-13 20:55                     ` Krakora Robert-B42341
2012-11-13 21:11                       ` Krakora Robert-B42341
2012-11-13 20:52                   ` Krakora Robert-B42341
2012-11-14  8:02                   ` David Henningsson
2012-11-14 12:55                     ` Krakora Robert-B42341
2012-11-14 19:49                     ` Trent Piepho
2012-11-14 20:03                       ` Rémi Denis-Courmont
2012-11-14 20:06                         ` Krakora Robert-B42341
2012-11-14 20:54                         ` Trent Piepho
2012-11-14 21:19                           ` Rémi Denis-Courmont
2012-11-15  1:52                             ` Krakora Robert-B42341
2012-11-15  7:39                       ` Takashi Iwai
2012-11-15 13:05                         ` Krakora Robert-B42341

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.