aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-01-07 09:36:31 -0500
committerJaroslav Kysela <perex@perex.cz>2010-01-07 09:48:13 -0500
commit1250932e48d3b698415b1f04775433cf1da688d6 (patch)
tree58d25383b6fa4e083f24dfc9d51ad4339ff7dece
parentf240406babfe1526998e10583ea5eccc2676a433 (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.h3
-rw-r--r--sound/core/pcm_lib.c30
-rw-r--r--sound/core/pcm_native.c6
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);
839int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); 840int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
840int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, 841int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
841 unsigned int cmd, void *arg); 842 unsigned int cmd, void *arg);
843int snd_pcm_update_state(struct snd_pcm_substream *substream,
844 struct snd_pcm_runtime *runtime);
842int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); 845int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
843int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); 846int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
844int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); 847int 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
266static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, 266int 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
562static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, 564static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,