diff options
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r-- | sound/core/pcm_lib.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f1341308bed..62e90b862a0 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -128,7 +128,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } } -static void pcm_debug_name(struct snd_pcm_substream *substream, +#ifdef CONFIG_SND_DEBUG +void snd_pcm_debug_name(struct snd_pcm_substream *substream, char *name, size_t len) { snprintf(name, len, "pcmC%dD%d%c:%d", @@ -137,6 +138,8 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, substream->stream ? 'c' : 'p', substream->number); } +EXPORT_SYMBOL(snd_pcm_debug_name); +#endif #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ @@ -168,7 +171,7 @@ static void xrun(struct snd_pcm_substream *substream) snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { char name[16]; - pcm_debug_name(substream, name, sizeof(name)); + snd_pcm_debug_name(substream, name, sizeof(name)); snd_printd(KERN_DEBUG "XRUN: %s\n", name); dump_stack_on_xrun(substream); } @@ -243,7 +246,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream) return; if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) return; - pcm_debug_name(substream, name, sizeof(name)); + snd_pcm_debug_name(substream, name, sizeof(name)); for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { entry = &log->entries[idx]; if (entry->period_size == 0) @@ -319,7 +322,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (pos >= runtime->buffer_size) { if (printk_ratelimit()) { char name[16]; - pcm_debug_name(substream, name, sizeof(name)); + snd_pcm_debug_name(substream, name, sizeof(name)); xrun_log_show(substream); snd_printd(KERN_ERR "BUG: %s, pos = %ld, " "buffer size = %ld, period size = %ld\n", @@ -364,7 +367,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (xrun_debug(substream, in_interrupt ? XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { char name[16]; - pcm_debug_name(substream, name, sizeof(name)); + snd_pcm_debug_name(substream, name, sizeof(name)); snd_printd("%s_update: %s: pos=%u/%u/%u, " "hwptr=%ld/%ld/%ld/%ld\n", in_interrupt ? "period" : "hwptr", @@ -1758,6 +1761,10 @@ static int wait_for_avail(struct snd_pcm_substream *substream, snd_pcm_uframes_t avail = 0; long wait_time, tout; + init_waitqueue_entry(&wait, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&runtime->tsleep, &wait); + if (runtime->no_period_wakeup) wait_time = MAX_SCHEDULE_TIMEOUT; else { @@ -1768,16 +1775,32 @@ static int wait_for_avail(struct snd_pcm_substream *substream, } wait_time = msecs_to_jiffies(wait_time * 1000); } - init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->tsleep, &wait); + for (;;) { if (signal_pending(current)) { err = -ERESTARTSYS; break; } + + /* + * We need to check if space became available already + * (and thus the wakeup happened already) first to close + * the race of space already having become available. + * This check must happen after been added to the waitqueue + * and having current state be INTERRUPTIBLE. + */ + if (is_playback) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); + if (avail >= runtime->twake) + break; snd_pcm_stream_unlock_irq(substream); - tout = schedule_timeout_interruptible(wait_time); + + tout = schedule_timeout(wait_time); + snd_pcm_stream_lock_irq(substream); + set_current_state(TASK_INTERRUPTIBLE); switch (runtime->status->state) { case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; @@ -1803,14 +1826,9 @@ static int wait_for_avail(struct snd_pcm_substream *substream, err = -EIO; break; } - if (is_playback) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail >= runtime->twake) - break; } _endloop: + set_current_state(TASK_RUNNING); remove_wait_queue(&runtime->tsleep, &wait); *availp = avail; return err; |