diff options
author | Jaroslav Kysela <perex@perex.cz> | 2010-01-07 09:36:31 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2010-01-07 09:48:13 -0500 |
commit | 1250932e48d3b698415b1f04775433cf1da688d6 (patch) | |
tree | 58d25383b6fa4e083f24dfc9d51ad4339ff7dece | |
parent | f240406babfe1526998e10583ea5eccc2676a433 (diff) |
ALSA: pcm_lib - optimize wake_up() calls for PCM I/O
As noted by pl bossart <bossart.nospam@gmail.com>, the PCM I/O routines
(snd_pcm_lib_write1, snd_pcm_lib_read1) should block wake_up() calls
until all samples are not processed.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | include/sound/pcm.h | 3 | ||||
-rw-r--r-- | sound/core/pcm_lib.c | 30 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 6 |
3 files changed, 27 insertions, 12 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index fe1b131842be..e26fb3c58037 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -311,6 +311,7 @@ struct snd_pcm_runtime { | |||
311 | struct snd_pcm_mmap_control *control; | 311 | struct snd_pcm_mmap_control *control; |
312 | 312 | ||
313 | /* -- locking / scheduling -- */ | 313 | /* -- locking / scheduling -- */ |
314 | unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ | ||
314 | wait_queue_head_t sleep; | 315 | wait_queue_head_t sleep; |
315 | struct fasync_struct *fasync; | 316 | struct fasync_struct *fasync; |
316 | 317 | ||
@@ -839,6 +840,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); | |||
839 | int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); | 840 | int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); |
840 | int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | 841 | int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, |
841 | unsigned int cmd, void *arg); | 842 | unsigned int cmd, void *arg); |
843 | int snd_pcm_update_state(struct snd_pcm_substream *substream, | ||
844 | struct snd_pcm_runtime *runtime); | ||
842 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); | 845 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); |
843 | int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); | 846 | int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); |
844 | int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); | 847 | int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 70a4f7428d78..a63226232ef4 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -263,8 +263,8 @@ static void xrun_log_show(struct snd_pcm_substream *substream) | |||
263 | 263 | ||
264 | #endif | 264 | #endif |
265 | 265 | ||
266 | static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | 266 | int snd_pcm_update_state(struct snd_pcm_substream *substream, |
267 | struct snd_pcm_runtime *runtime) | 267 | struct snd_pcm_runtime *runtime) |
268 | { | 268 | { |
269 | snd_pcm_uframes_t avail; | 269 | snd_pcm_uframes_t avail; |
270 | 270 | ||
@@ -285,7 +285,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | |||
285 | return -EPIPE; | 285 | return -EPIPE; |
286 | } | 286 | } |
287 | } | 287 | } |
288 | if (avail >= runtime->control->avail_min) | 288 | if (!runtime->nowake && avail >= runtime->control->avail_min) |
289 | wake_up(&runtime->sleep); | 289 | wake_up(&runtime->sleep); |
290 | return 0; | 290 | return 0; |
291 | } | 291 | } |
@@ -441,7 +441,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
441 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | 441 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
442 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | 442 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
443 | 443 | ||
444 | return snd_pcm_update_hw_ptr_post(substream, runtime); | 444 | return snd_pcm_update_state(substream, runtime); |
445 | } | 445 | } |
446 | 446 | ||
447 | /* CAUTION: call it with irq disabled */ | 447 | /* CAUTION: call it with irq disabled */ |
@@ -1792,6 +1792,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1792 | goto _end_unlock; | 1792 | goto _end_unlock; |
1793 | } | 1793 | } |
1794 | 1794 | ||
1795 | runtime->nowake = 1; | ||
1795 | while (size > 0) { | 1796 | while (size > 0) { |
1796 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1797 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
1797 | snd_pcm_uframes_t avail; | 1798 | snd_pcm_uframes_t avail; |
@@ -1813,15 +1814,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1813 | if (frames > cont) | 1814 | if (frames > cont) |
1814 | frames = cont; | 1815 | frames = cont; |
1815 | if (snd_BUG_ON(!frames)) { | 1816 | if (snd_BUG_ON(!frames)) { |
1817 | runtime->nowake = 0; | ||
1816 | snd_pcm_stream_unlock_irq(substream); | 1818 | snd_pcm_stream_unlock_irq(substream); |
1817 | return -EINVAL; | 1819 | return -EINVAL; |
1818 | } | 1820 | } |
1819 | appl_ptr = runtime->control->appl_ptr; | 1821 | appl_ptr = runtime->control->appl_ptr; |
1820 | appl_ofs = appl_ptr % runtime->buffer_size; | 1822 | appl_ofs = appl_ptr % runtime->buffer_size; |
1821 | snd_pcm_stream_unlock_irq(substream); | 1823 | snd_pcm_stream_unlock_irq(substream); |
1822 | if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) | 1824 | err = transfer(substream, appl_ofs, data, offset, frames); |
1823 | goto _end; | ||
1824 | snd_pcm_stream_lock_irq(substream); | 1825 | snd_pcm_stream_lock_irq(substream); |
1826 | if (err < 0) | ||
1827 | goto _end_unlock; | ||
1825 | switch (runtime->status->state) { | 1828 | switch (runtime->status->state) { |
1826 | case SNDRV_PCM_STATE_XRUN: | 1829 | case SNDRV_PCM_STATE_XRUN: |
1827 | err = -EPIPE; | 1830 | err = -EPIPE; |
@@ -1850,8 +1853,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1850 | } | 1853 | } |
1851 | } | 1854 | } |
1852 | _end_unlock: | 1855 | _end_unlock: |
1856 | runtime->nowake = 0; | ||
1857 | if (xfer > 0 && err >= 0) | ||
1858 | snd_pcm_update_state(substream, runtime); | ||
1853 | snd_pcm_stream_unlock_irq(substream); | 1859 | snd_pcm_stream_unlock_irq(substream); |
1854 | _end: | ||
1855 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 1860 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
1856 | } | 1861 | } |
1857 | 1862 | ||
@@ -2009,6 +2014,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2009 | goto _end_unlock; | 2014 | goto _end_unlock; |
2010 | } | 2015 | } |
2011 | 2016 | ||
2017 | runtime->nowake = 1; | ||
2012 | while (size > 0) { | 2018 | while (size > 0) { |
2013 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2019 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
2014 | snd_pcm_uframes_t avail; | 2020 | snd_pcm_uframes_t avail; |
@@ -2037,15 +2043,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2037 | if (frames > cont) | 2043 | if (frames > cont) |
2038 | frames = cont; | 2044 | frames = cont; |
2039 | if (snd_BUG_ON(!frames)) { | 2045 | if (snd_BUG_ON(!frames)) { |
2046 | runtime->nowake = 0; | ||
2040 | snd_pcm_stream_unlock_irq(substream); | 2047 | snd_pcm_stream_unlock_irq(substream); |
2041 | return -EINVAL; | 2048 | return -EINVAL; |
2042 | } | 2049 | } |
2043 | appl_ptr = runtime->control->appl_ptr; | 2050 | appl_ptr = runtime->control->appl_ptr; |
2044 | appl_ofs = appl_ptr % runtime->buffer_size; | 2051 | appl_ofs = appl_ptr % runtime->buffer_size; |
2045 | snd_pcm_stream_unlock_irq(substream); | 2052 | snd_pcm_stream_unlock_irq(substream); |
2046 | if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) | 2053 | err = transfer(substream, appl_ofs, data, offset, frames); |
2047 | goto _end; | ||
2048 | snd_pcm_stream_lock_irq(substream); | 2054 | snd_pcm_stream_lock_irq(substream); |
2055 | if (err < 0) | ||
2056 | goto _end_unlock; | ||
2049 | switch (runtime->status->state) { | 2057 | switch (runtime->status->state) { |
2050 | case SNDRV_PCM_STATE_XRUN: | 2058 | case SNDRV_PCM_STATE_XRUN: |
2051 | err = -EPIPE; | 2059 | err = -EPIPE; |
@@ -2068,8 +2076,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2068 | xfer += frames; | 2076 | xfer += frames; |
2069 | } | 2077 | } |
2070 | _end_unlock: | 2078 | _end_unlock: |
2079 | runtime->nowake = 0; | ||
2080 | if (xfer > 0 && err >= 0) | ||
2081 | snd_pcm_update_state(substream, runtime); | ||
2071 | snd_pcm_stream_unlock_irq(substream); | 2082 | snd_pcm_stream_unlock_irq(substream); |
2072 | _end: | ||
2073 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2083 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
2074 | } | 2084 | } |
2075 | 2085 | ||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8e777f71717c..27284f628361 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -516,6 +516,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
516 | struct snd_pcm_sw_params *params) | 516 | struct snd_pcm_sw_params *params) |
517 | { | 517 | { |
518 | struct snd_pcm_runtime *runtime; | 518 | struct snd_pcm_runtime *runtime; |
519 | int err; | ||
519 | 520 | ||
520 | if (PCM_RUNTIME_CHECK(substream)) | 521 | if (PCM_RUNTIME_CHECK(substream)) |
521 | return -ENXIO; | 522 | return -ENXIO; |
@@ -540,6 +541,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
540 | if (params->silence_threshold > runtime->buffer_size) | 541 | if (params->silence_threshold > runtime->buffer_size) |
541 | return -EINVAL; | 542 | return -EINVAL; |
542 | } | 543 | } |
544 | err = 0; | ||
543 | snd_pcm_stream_lock_irq(substream); | 545 | snd_pcm_stream_lock_irq(substream); |
544 | runtime->tstamp_mode = params->tstamp_mode; | 546 | runtime->tstamp_mode = params->tstamp_mode; |
545 | runtime->period_step = params->period_step; | 547 | runtime->period_step = params->period_step; |
@@ -553,10 +555,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
553 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 555 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
554 | runtime->silence_size > 0) | 556 | runtime->silence_size > 0) |
555 | snd_pcm_playback_silence(substream, ULONG_MAX); | 557 | snd_pcm_playback_silence(substream, ULONG_MAX); |
556 | wake_up(&runtime->sleep); | 558 | err = snd_pcm_update_state(substream, runtime); |
557 | } | 559 | } |
558 | snd_pcm_stream_unlock_irq(substream); | 560 | snd_pcm_stream_unlock_irq(substream); |
559 | return 0; | 561 | return err; |
560 | } | 562 | } |
561 | 563 | ||
562 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, | 564 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, |