Takashi Iwai
7a3b45a028
- backport fixes from upstream tree: 0031-pcm-support-for-audio-timestamps.patch 0032-pcm-fix-64-bit-SNDRV_PCM_IOCTL_STATUS-ABI-breakage.patch 0033-PCM-Fix-memory-leak-for-pcm-empty-and-asym-plugins.patch 0034-Reduce-compilation-warnings.patch 0035-PCM-Avoid-busy-loop-in-snd_pcm_write_areas-with-rate.patch OBS-URL: https://build.opensuse.org/request/show/141190 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=115
223 lines
8.3 KiB
Diff
223 lines
8.3 KiB
Diff
From 3fd4ab9be0db7c7430ebd258f2717a976381715d Mon Sep 17 00:00:00 2001
|
|
From: Takashi Iwai <tiwai@suse.de>
|
|
Date: Tue, 13 Nov 2012 16:16:26 +0100
|
|
Subject: [PATCH 35/35] PCM: Avoid busy loop in snd_pcm_write_areas() with
|
|
rate plugin
|
|
|
|
snd_pcm_write_areas() tries to wait until avail >= avail_min condition
|
|
is satisfied. This doesn't work always well when a rate plugin is in
|
|
the play.
|
|
|
|
When a partial data with a smaller size than a period is written, the
|
|
rate plugin doesn't transfer the data immediately to the slave PCM,
|
|
but kept in an internal buffer and it changes only the hwptr of the
|
|
plugin. Thus, the condition "avail < avail_min" is triggered for a
|
|
wait check although the underlying slave PCM has enough room. This
|
|
results in a call of snd_pcm_wait() which returns immediately after
|
|
poll() call, and the snd_pcm_write_areas() loop continues. As a
|
|
consequence, it falls into a CPU hog.
|
|
|
|
This patch fixes that busy loop by introducing a new fast_ops to check
|
|
the availability for wait of avail_min. Then a plugin can ask the
|
|
slave PCM whether the wait is required (or possible).
|
|
|
|
A few plugins like multi plugin need a special handling. Otherwise a
|
|
generic plugin function can be used.
|
|
|
|
Reported-by: Trent Piepho <tpiepho@gmail.com>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
src/pcm/pcm.c | 8 ++++----
|
|
src/pcm/pcm_generic.c | 6 ++++++
|
|
src/pcm/pcm_generic.h | 4 +++-
|
|
src/pcm/pcm_hooks.c | 1 +
|
|
src/pcm/pcm_local.h | 11 +++++++++++
|
|
src/pcm/pcm_meter.c | 1 +
|
|
src/pcm/pcm_mmap_emul.c | 1 +
|
|
src/pcm/pcm_multi.c | 8 ++++++++
|
|
src/pcm/pcm_plugin.c | 1 +
|
|
src/pcm/pcm_rate.c | 1 +
|
|
10 files changed, 37 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
|
|
index 359d295..f8b68ed 100644
|
|
--- a/src/pcm/pcm.c
|
|
+++ b/src/pcm/pcm.c
|
|
@@ -2357,7 +2357,7 @@ int snd_pcm_open_named_slave(snd_pcm_t **pcmp, const char *name,
|
|
*/
|
|
int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
|
|
{
|
|
- if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min) {
|
|
+ if (!snd_pcm_may_wait_for_avail_min(pcm, snd_pcm_mmap_avail(pcm))) {
|
|
/* check more precisely */
|
|
switch (snd_pcm_state(pcm)) {
|
|
case SND_PCM_STATE_XRUN:
|
|
@@ -6776,14 +6776,14 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
|
|
goto _end;
|
|
}
|
|
if ((state == SND_PCM_STATE_RUNNING &&
|
|
- (snd_pcm_uframes_t)avail < pcm->avail_min &&
|
|
- size > (snd_pcm_uframes_t)avail)) {
|
|
+ size > (snd_pcm_uframes_t)avail &&
|
|
+ snd_pcm_may_wait_for_avail_min(pcm, avail))) {
|
|
if (pcm->mode & SND_PCM_NONBLOCK) {
|
|
err = -EAGAIN;
|
|
goto _end;
|
|
}
|
|
|
|
- err = snd_pcm_wait(pcm, -1);
|
|
+ err = snd_pcm_wait_nocheck(pcm, -1);
|
|
if (err < 0)
|
|
break;
|
|
goto _again;
|
|
diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c
|
|
index d56e5d3..5fc4888 100644
|
|
--- a/src/pcm/pcm_generic.c
|
|
+++ b/src/pcm/pcm_generic.c
|
|
@@ -341,4 +341,10 @@ int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
|
|
return snd_pcm_set_chmap(generic->slave, map);
|
|
}
|
|
|
|
+int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)
|
|
+{
|
|
+ snd_pcm_generic_t *generic = pcm->private_data;
|
|
+ return snd_pcm_may_wait_for_avail_min(generic->slave, snd_pcm_mmap_avail(generic->slave));
|
|
+}
|
|
+
|
|
#endif /* DOC_HIDDEN */
|
|
diff --git a/src/pcm/pcm_generic.h b/src/pcm/pcm_generic.h
|
|
index 916c6ec..d189077 100644
|
|
--- a/src/pcm/pcm_generic.h
|
|
+++ b/src/pcm/pcm_generic.h
|
|
@@ -109,6 +109,8 @@ typedef struct {
|
|
snd1_pcm_generic_get_chmap
|
|
#define snd_pcm_generic_set_chmap \
|
|
snd1_pcm_generic_set_chmap
|
|
+#define snd_pcm_generic_may_wait_for_avail_min \
|
|
+ snd1_pcm_generic_may_wait_for_avail_min
|
|
|
|
int snd_pcm_generic_close(snd_pcm_t *pcm);
|
|
int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock);
|
|
@@ -158,5 +160,5 @@ int snd_pcm_generic_munmap(snd_pcm_t *pcm);
|
|
snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm);
|
|
snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm);
|
|
int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
|
|
-
|
|
+int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail);
|
|
|
|
diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c
|
|
index 0feb4a3..f837282 100644
|
|
--- a/src/pcm/pcm_hooks.c
|
|
+++ b/src/pcm/pcm_hooks.c
|
|
@@ -199,6 +199,7 @@ static const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = {
|
|
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
.poll_revents = snd_pcm_generic_poll_revents,
|
|
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
|
|
};
|
|
|
|
/**
|
|
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
|
|
index e7798fd..8cf7c3d 100644
|
|
--- a/src/pcm/pcm_local.h
|
|
+++ b/src/pcm/pcm_local.h
|
|
@@ -177,6 +177,7 @@ typedef struct {
|
|
int (*poll_descriptors_count)(snd_pcm_t *pcm);
|
|
int (*poll_descriptors)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
|
|
int (*poll_revents)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
|
|
+ int (*may_wait_for_avail_min)(snd_pcm_t *pcm, snd_pcm_uframes_t avail);
|
|
} snd_pcm_fast_ops_t;
|
|
|
|
struct _snd_pcm {
|
|
@@ -984,3 +985,13 @@ _snd_pcm_parse_config_chmaps(snd_config_t *conf);
|
|
snd_pcm_chmap_t *
|
|
_snd_pcm_choose_fixed_chmap(snd_pcm_t *pcm, snd_pcm_chmap_query_t * const *maps);
|
|
|
|
+/* return true if the PCM stream may wait to get avail_min space */
|
|
+static inline int snd_pcm_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail)
|
|
+{
|
|
+ if (avail >= pcm->avail_min)
|
|
+ return 0;
|
|
+ if (pcm->fast_ops->may_wait_for_avail_min)
|
|
+ return pcm->fast_ops->may_wait_for_avail_min(pcm, avail);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c
|
|
index 42a125e..e60b92d 100644
|
|
--- a/src/pcm/pcm_meter.c
|
|
+++ b/src/pcm/pcm_meter.c
|
|
@@ -545,6 +545,7 @@ static const snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = {
|
|
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
.poll_revents = snd_pcm_generic_poll_revents,
|
|
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
|
|
};
|
|
|
|
/**
|
|
diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c
|
|
index 811cb1c..67d2e05 100644
|
|
--- a/src/pcm/pcm_mmap_emul.c
|
|
+++ b/src/pcm/pcm_mmap_emul.c
|
|
@@ -400,6 +400,7 @@ static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = {
|
|
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
.poll_revents = snd_pcm_generic_poll_revents,
|
|
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
|
|
};
|
|
|
|
#ifndef DOC_HIDDEN
|
|
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c
|
|
index ffb1b53..2db82c0 100644
|
|
--- a/src/pcm/pcm_multi.c
|
|
+++ b/src/pcm/pcm_multi.c
|
|
@@ -739,6 +739,13 @@ static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
|
|
return 0;
|
|
}
|
|
|
|
+static int snd_pcm_multi_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail)
|
|
+{
|
|
+ snd_pcm_multi_t *multi = pcm->private_data;
|
|
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
|
|
+ return snd_pcm_may_wait_for_avail_min(slave, snd_pcm_mmap_avail(slave));
|
|
+}
|
|
+
|
|
static snd_pcm_chmap_query_t **snd_pcm_multi_query_chmaps(snd_pcm_t *pcm)
|
|
{
|
|
snd_pcm_multi_t *multi = pcm->private_data;
|
|
@@ -937,6 +944,7 @@ static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
|
|
.poll_descriptors_count = snd_pcm_multi_poll_descriptors_count,
|
|
.poll_descriptors = snd_pcm_multi_poll_descriptors,
|
|
.poll_revents = snd_pcm_multi_poll_revents,
|
|
+ .may_wait_for_avail_min = snd_pcm_multi_may_wait_for_avail_min,
|
|
};
|
|
|
|
/**
|
|
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
|
|
index d88e117..96218a8 100644
|
|
--- a/src/pcm/pcm_plugin.c
|
|
+++ b/src/pcm/pcm_plugin.c
|
|
@@ -570,6 +570,7 @@ const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
|
|
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
.poll_revents = snd_pcm_generic_poll_revents,
|
|
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
|
|
};
|
|
|
|
#endif
|
|
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
|
|
index 4ba8521..54a3e67 100644
|
|
--- a/src/pcm/pcm_rate.c
|
|
+++ b/src/pcm/pcm_rate.c
|
|
@@ -1234,6 +1234,7 @@ static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = {
|
|
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
.poll_revents = snd_pcm_rate_poll_revents,
|
|
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
|
|
};
|
|
|
|
static const snd_pcm_ops_t snd_pcm_rate_ops = {
|
|
--
|
|
1.8.0
|
|
|