[alsa-devel] snd_pcm_drain and lock-ups
Hi all,
I've followed Arve Knudsen over here. I am getting a lock-up when calling snd_pcm_drain(). This happens when using espeak, which is using portaudio. Portaudio calls snd_pcm_drain while trying to recover from a XRUN. snd_pcm_drain is calling snd_pcm_rate_drain in my case. snd_pcm_rate_drain then calls snd_pcm_wait. snd_pcm_wait first checks if snd_pcm_mmap_avail(pcm) >= pcm->avail_min. snd_pcm_map_avail is returning a number less than 300, often between 135 and 140 but not always, where pcm->avail_min == 1024. So it does not check for the XRUN state since it is conditional on snd_pcm_mmap_avail returning >= 1024. This is on my laptop, which is running Linux 2.6.22 and alsa-lib 1.0.15-rc1 and uses the snd-intel8x0 driver.
Does this give people enough information to tell what might be going on? I have a small test program that causes the lock-up on my laptop where the rate plugin gets used (it sometimes locks up immediately, sometimes after a few seconds), but it needs espeak and portaudio to be installed.
Thanks,
-- Mike Gorse / AIM:linvortex / http://mgorse.freeshell.org --
Hi again,
I posted last week because I am getting lockups when portaudio calls snd_pcm_drain, and snd_pcm_rate_drain calls snd_pcm_wait on its slave.
Now that I've looked at this more, I'm seeing that it involves dmix, since a dmix plugin is behind the rate plugin.
The dmix code in alsa-lib is setting a xrun state because snd_pcm_mmap_playback_avail returns a large value.
snd_pcm_wait is then called on the slave of the rate pcm, which is a pcm with a type of SND_PCM_TYPE_ROUTE whose slave is the dmix, but the route pcm is returning a different value for snd_pcm_mmap_avail than the dmix pcm, so it is not triggering snd_pcm_wait to check for a xrun.
The following patch stops snd_pcm_wait from locking up for me, although I'm not sure if it is the best way of handling things:
--- src/pcm/pcm.c.orig 2007-09-12 05:20:32.000000000 -0400 +++ src/pcm/pcm.c 2007-09-19 19:52:10.000000000 -0400 @@ -2255,7 +2255,7 @@ */ int snd_pcm_wait(snd_pcm_t *pcm, int timeout) { - if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min) { + if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min || pcm->type == SND_PCM_TYPE_ROUTE) { /* check more precisely */ switch (snd_pcm_state(pcm)) { case SND_PCM_STATE_XRUN:
Thanks, -- Mike Gorse / AIM:linvortex / http://mgorse.freeshell.org --
On Wed, 19 Sep 2007, Mike Gorse wrote:
Hi again,
I posted last week because I am getting lockups when portaudio calls snd_pcm_drain, and snd_pcm_rate_drain calls snd_pcm_wait on its slave.
Now that I've looked at this more, I'm seeing that it involves dmix, since a dmix plugin is behind the rate plugin.
The dmix code in alsa-lib is setting a xrun state because snd_pcm_mmap_playback_avail returns a large value.
snd_pcm_wait is then called on the slave of the rate pcm, which is a pcm with a type of SND_PCM_TYPE_ROUTE whose slave is the dmix, but the route pcm is returning a different value for snd_pcm_mmap_avail than the dmix pcm, so it is not triggering snd_pcm_wait to check for a xrun.
The following patch stops snd_pcm_wait from locking up for me, although I'm not sure if it is the best way of handling things:
--- src/pcm/pcm.c.orig 2007-09-12 05:20:32.000000000 -0400 +++ src/pcm/pcm.c 2007-09-19 19:52:10.000000000 -0400 @@ -2255,7 +2255,7 @@ */ int snd_pcm_wait(snd_pcm_t *pcm, int timeout) {
- if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min) {
- if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min || pcm->type == SND_PCM_TYPE_ROUTE) { /* check more precisely */ switch (snd_pcm_state(pcm)) { case SND_PCM_STATE_XRUN:
I think that better fix is to change the code in snd_pcm_rate_drain(). You can set avail_min to 1 there, so condition in snd_pcm_wait() will match.
Does this patch help?
diff -r 68d71239d651 src/pcm/pcm_rate.c --- a/src/pcm/pcm_rate.c Thu Sep 20 13:20:03 2007 +0200 +++ b/src/pcm/pcm_rate.c Fri Sep 21 10:14:41 2007 +0200 @@ -1076,10 +1076,10 @@ static int snd_pcm_rate_drain(snd_pcm_t snd_pcm_uframes_t size, ofs, saved_avail_min; snd_pcm_sw_params_t sw_params;
- /* temporarily set avail_min to one period */ + /* temporarily set avail_min to one */ sw_params = rate->sw_params; saved_avail_min = sw_params.avail_min; - sw_params.avail_min = rate->gen.slave->period_size; + sw_params.avail_min = 1; snd_pcm_sw_params(rate->gen.slave, &sw_params);
size = rate->appl_ptr - rate->last_commit_ptr;
Jaroslav
----- Jaroslav Kysela perex@suse.cz Linux Kernel Sound Maintainer ALSA Project, SUSE Labs
On Fri, 21 Sep 2007, Jaroslav Kysela wrote:
I posted last week because I am getting lockups when portaudio calls snd_pcm_drain, and snd_pcm_rate_drain calls snd_pcm_wait on its slave.
Now that I've looked at this more, I'm seeing that it involves dmix, since a dmix plugin is behind the rate plugin.
The dmix code in alsa-lib is setting a xrun state because snd_pcm_mmap_playback_avail returns a large value.
snd_pcm_wait is then called on the slave of the rate pcm, which is a pcm with a type of SND_PCM_TYPE_ROUTE whose slave is the dmix, but the route pcm is returning a different value for snd_pcm_mmap_avail than the dmix pcm, so it is not triggering snd_pcm_wait to check for a xrun.
I think that better fix is to change the code in snd_pcm_rate_drain(). You can set avail_min to 1 there, so condition in snd_pcm_wait() will match.
Does this patch help?
diff -r 68d71239d651 src/pcm/pcm_rate.c --- a/src/pcm/pcm_rate.c Thu Sep 20 13:20:03 2007 +0200 +++ b/src/pcm/pcm_rate.c Fri Sep 21 10:14:41 2007 +0200 @@ -1076,10 +1076,10 @@ static int snd_pcm_rate_drain(snd_pcm_t snd_pcm_uframes_t size, ofs, saved_avail_min; snd_pcm_sw_params_t sw_params;
/* temporarily set avail_min to one period */
sw_params = rate->sw_params; saved_avail_min = sw_params.avail_min;/* temporarily set avail_min to one */
sw_params.avail_min = rate->gen.slave->period_size;
sw_params.avail_min = 1;
snd_pcm_sw_params(rate->gen.slave, &sw_params);
size = rate->appl_ptr - rate->last_commit_ptr;
Jaroslav
Yes, that also works.
Thanks, -Mike
I posted last week because I am getting lockups when portaudio calls snd_pcm_drain, and snd_pcm_rate_drain calls snd_pcm_wait on its slave.
Now that I've looked at this more, I'm seeing that it involves dmix, since a dmix plugin is behind the rate plugin.
The dmix code in alsa-lib is setting a xrun state because snd_pcm_mmap_playback_avail returns a large value.
snd_pcm_wait is then called on the slave of the rate pcm, which is a pcm with a type of SND_PCM_TYPE_ROUTE whose slave is the dmix, but the route pcm is returning a different value for snd_pcm_mmap_avail than the dmix pcm, so it is not triggering snd_pcm_wait to check for a xrun.
I think that better fix is to change the code in snd_pcm_rate_drain(). You can set avail_min to 1 there, so condition in snd_pcm_wait() will match.
Does this patch help?
diff -r 68d71239d651 src/pcm/pcm_rate.c --- a/src/pcm/pcm_rate.c Thu Sep 20 13:20:03 2007 +0200 +++ b/src/pcm/pcm_rate.c Fri Sep 21 10:14:41 2007 +0200 @@ -1076,10 +1076,10 @@ static int snd_pcm_rate_drain(snd_pcm_t snd_pcm_uframes_t size, ofs, saved_avail_min; snd_pcm_sw_params_t sw_params;
/* temporarily set avail_min to one period */
sw_params = rate->sw_params; saved_avail_min = sw_params.avail_min;/* temporarily set avail_min to one */
sw_params.avail_min = rate->gen.slave->period_size;
sw_params.avail_min = 1;
snd_pcm_sw_params(rate->gen.slave, &sw_params);
size = rate->appl_ptr - rate->last_commit_ptr;
Jaroslav
Unfortunately, I just discovered that this patch (now in alsa-lib 1.0.15-rc3) does not always solve my problem. It does most of the time, but snd_pcm_avail on the route occasionally returns 0, which is less than 1, so once in a while I still get a lock-up. I can't change the 1 to a 0 in snd_pcm_drain since snd_pcm_sw_params aborts if sw_params->avail_min == 0.
My original approach of checking for SND_PCM_TYPE_ROUTE in snd_pcm_wait() would still work.
It looks as though there is a buffer to fill which is included when snd_pcm_mmap_avail looks at the dmix pcm but not when it looks at the route in between the rate and the dmix.
-Mike G-
On Sun, 7 Oct 2007, Mike Gorse wrote:
I posted last week because I am getting lockups when portaudio calls snd_pcm_drain, and snd_pcm_rate_drain calls snd_pcm_wait on its slave.
Now that I've looked at this more, I'm seeing that it involves dmix, since a dmix plugin is behind the rate plugin.
The dmix code in alsa-lib is setting a xrun state because snd_pcm_mmap_playback_avail returns a large value.
snd_pcm_wait is then called on the slave of the rate pcm, which is a pcm with a type of SND_PCM_TYPE_ROUTE whose slave is the dmix, but the route pcm is returning a different value for snd_pcm_mmap_avail than the dmix pcm, so it is not triggering snd_pcm_wait to check for a xrun.
I think that better fix is to change the code in snd_pcm_rate_drain(). You can set avail_min to 1 there, so condition in snd_pcm_wait() will match.
Does this patch help?
diff -r 68d71239d651 src/pcm/pcm_rate.c --- a/src/pcm/pcm_rate.c Thu Sep 20 13:20:03 2007 +0200 +++ b/src/pcm/pcm_rate.c Fri Sep 21 10:14:41 2007 +0200 @@ -1076,10 +1076,10 @@ static int snd_pcm_rate_drain(snd_pcm_t snd_pcm_uframes_t size, ofs, saved_avail_min; snd_pcm_sw_params_t sw_params;
/* temporarily set avail_min to one period */
/* temporarily set avail_min to one */
sw_params = rate->sw_params; saved_avail_min = sw_params.avail_min;
sw_params.avail_min = rate->gen.slave->period_size;
sw_params.avail_min = 1;
snd_pcm_sw_params(rate->gen.slave, &sw_params);
size = rate->appl_ptr - rate->last_commit_ptr;
Jaroslav
Unfortunately, I just discovered that this patch (now in alsa-lib 1.0.15-rc3) does not always solve my problem. It does most of the time, but snd_pcm_avail on the route occasionally returns 0, which is less than 1, so once in a while I still get a lock-up. I can't change the 1 to a 0 in snd_pcm_drain since snd_pcm_sw_params aborts if sw_params->avail_min == 0.
My original approach of checking for SND_PCM_TYPE_ROUTE in snd_pcm_wait() would still work.
It looks as though there is a buffer to fill which is included when snd_pcm_mmap_avail looks at the dmix pcm but not when it looks at the route in between the rate and the dmix.
I think we're looking bug on wrong place. If dmix is in XRUN state, snd_pcm_poll_descriptors_revents() should return POLLERR, thus the check for XRUN should be done in snd_pcm_wait_nocheck() after revents checking.
Could you trace what occurs in your scenario in snd_pcm_wait_nocheck() ?
Thanks, Jaroslav
----- Jaroslav Kysela perex@suse.cz Linux Kernel Sound Maintainer ALSA Project, SUSE Labs
On Sun, 7 Oct 2007, Jaroslav Kysela wrote:
I am getting lockups when portaudio calls snd_pcm_drain, and snd_pcm_rate_drain calls snd_pcm_wait on its slave.
Now that I've looked at this more, I'm seeing that it involves dmix, since a dmix plugin is behind the rate plugin.
The dmix code in alsa-lib is setting a xrun state because snd_pcm_mmap_playback_avail returns a large value.
snd_pcm_wait is then called on the slave of the rate pcm, which is a pcm with a type of SND_PCM_TYPE_ROUTE whose slave is the dmix, but the route pcm is returning a different value for snd_pcm_mmap_avail than the dmix pcm, so it is not triggering snd_pcm_wait to check for a xrun.
...
I think we're looking bug on wrong place. If dmix is in XRUN state, snd_pcm_poll_descriptors_revents() should return POLLERR, thus the check for XRUN should be done in snd_pcm_wait_nocheck() after revents checking.
Could you trace what occurs in your scenario in snd_pcm_wait_nocheck() ?
Looking at the code suggests that snd_pcm_poll_descriptors_revents would return POLLERR if it ever got called, but it isn't called because poll() would have to return first, and it doesn't.
Thanks, -Mike
participants (2)
-
Jaroslav Kysela
-
Mike Gorse