Merge branch 'for-linus'
diff --git a/sound/core/timer.c b/sound/core/timer.c index 13d7378..5bc217a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c
@@ -489,10 +489,20 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, snd_timer_stop(timeri); if (timer) { + struct snd_timer_instance *slave; + bool busy; + timer->num_instances--; - /* wait, until the active callback is finished */ + /* unqueue then drain the slaves' callbacks before remove_slave_links() severs them */ spin_lock_irq(&timer->lock); - while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { + list_for_each_entry(slave, &timeri->slave_list_head, open_list) + list_del_init(&slave->ack_list); + for (;;) { + busy = timeri->flags & SNDRV_TIMER_IFLG_CALLBACK; + list_for_each_entry(slave, &timeri->slave_list_head, open_list) + busy |= slave->flags & SNDRV_TIMER_IFLG_CALLBACK; + if (!busy) + break; spin_unlock_irq(&timer->lock); udelay(10); spin_lock_irq(&timer->lock); @@ -927,12 +937,15 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ack_list_head = &timer->ack_list_head; else ack_list_head = &timer->sack_list_head; - if (list_empty(&ti->ack_list)) + /* don't requeue an instance whose callback is still running */ + if (list_empty(&ti->ack_list) && + !(ti->flags & SNDRV_TIMER_IFLG_CALLBACK)) list_add_tail(&ti->ack_list, ack_list_head); list_for_each_entry(ts, &ti->slave_active_head, active_list) { ts->pticks = ti->pticks; ts->resolution = resolution; - if (list_empty(&ts->ack_list)) + if (list_empty(&ts->ack_list) && + !(ts->flags & SNDRV_TIMER_IFLG_CALLBACK)) list_add_tail(&ts->ack_list, ack_list_head); } }