[ALSA] Fix possible races in timer callbacks
Takashi Iwai [Fri, 18 Nov 2005 17:52:14 +0000 (18:52 +0100)]
Fix possible races in timer callbacks.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

sound/core/timer.c
sound/drivers/dummy.c
sound/drivers/mpu401/mpu401_uart.c
sound/drivers/opl3/opl3_midi.c
sound/pci/korg1212/korg1212.c
sound/synth/emux/emux_synth.c

index 74637ce..6aad411 100644 (file)
@@ -662,12 +662,13 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
        struct snd_timer_instance *ti, *ts;
        unsigned long resolution, ticks;
        struct list_head *p, *q, *n, *ack_list_head;
+       unsigned long flags;
        int use_tasklet = 0;
 
        if (timer == NULL)
                return;
 
-       spin_lock(&timer->lock);
+       spin_lock_irqsave(&timer->lock, flags);
 
        /* remember the current resolution */
        if (timer->hw.c_resolution)
@@ -752,7 +753,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
 
        /* do we have any slow callbacks? */
        use_tasklet = !list_empty(&timer->sack_list_head);
-       spin_unlock(&timer->lock);
+       spin_unlock_irqrestore(&timer->lock, flags);
 
        if (use_tasklet)
                tasklet_hi_schedule(&timer->task_queue);
index a276f7c..1861175 100644 (file)
@@ -231,8 +231,9 @@ static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream)
 static void snd_card_dummy_pcm_timer_function(unsigned long data)
 {
        struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data;
+       unsigned long flags;
        
-       spin_lock(&dpcm->lock);
+       spin_lock_irqsave(&dpcm->lock, flags);
        dpcm->timer.expires = 1 + jiffies;
        add_timer(&dpcm->timer);
        dpcm->pcm_irq_pos += dpcm->pcm_jiffie;
@@ -240,11 +241,10 @@ static void snd_card_dummy_pcm_timer_function(unsigned long data)
        dpcm->pcm_buf_pos %= dpcm->pcm_size;
        if (dpcm->pcm_irq_pos >= dpcm->pcm_count) {
                dpcm->pcm_irq_pos %= dpcm->pcm_count;
-               spin_unlock(&dpcm->lock);
+               spin_unlock_irqrestore(&dpcm->lock, flags);
                snd_pcm_period_elapsed(dpcm->substream);
-               spin_lock(&dpcm->lock);
-       }
-       spin_unlock(&dpcm->lock);
+       } else
+               spin_unlock_irqrestore(&dpcm->lock, flags);
 }
 
 static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream)
index ee67b52..8687ae3 100644 (file)
@@ -133,12 +133,13 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *reg
 static void snd_mpu401_uart_timer(unsigned long data)
 {
        struct snd_mpu401 *mpu = (struct snd_mpu401 *)data;
+       unsigned long flags;
 
-       spin_lock(&mpu->timer_lock);
+       spin_lock_irqsave(&mpu->timer_lock, flags);
        /*mpu->mode |= MPU401_MODE_TIMER;*/
        mpu->timer.expires = 1 + jiffies;
        add_timer(&mpu->timer);
-       spin_unlock(&mpu->timer_lock);
+       spin_unlock_irqrestore(&mpu->timer_lock, flags);
        if (mpu->rmidi)
                _snd_mpu401_uart_interrupt(mpu);
 }
index 48c480e..1b6f227 100644 (file)
@@ -238,10 +238,11 @@ void snd_opl3_timer_func(unsigned long data)
 {
 
        struct snd_opl3 *opl3 = (struct snd_opl3 *)data;
+       unsigned long flags;
        int again = 0;
        int i;
 
-       spin_lock(&opl3->sys_timer_lock);
+       spin_lock_irqsave(&opl3->sys_timer_lock, flags);
        for (i = 0; i < opl3->max_voices; i++) {
                struct snd_opl3_voice *vp = &opl3->voices[i];
                if (vp->state > 0 && vp->note_off_check) {
@@ -257,7 +258,7 @@ void snd_opl3_timer_func(unsigned long data)
        } else {
                opl3->sys_timer_status = 0;
        }
-       spin_unlock(&opl3->sys_timer_lock);
+       spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
 }
 
 /*
index a8a6a5c..4eddb51 100644 (file)
@@ -609,8 +609,9 @@ static void snd_korg1212_SendStopAndWait(struct snd_korg1212 *korg1212)
 static void snd_korg1212_timer_func(unsigned long data)
 {
         struct snd_korg1212 *korg1212 = (struct snd_korg1212 *) data;
+       unsigned long flags;
        
-       spin_lock(&korg1212->lock);
+       spin_lock_irqsave(&korg1212->lock, flags);
        if (korg1212->sharedBufferPtr->cardCommand == 0) {
                /* ack'ed */
                korg1212->stop_pending_cnt = 0;
@@ -632,7 +633,7 @@ static void snd_korg1212_timer_func(unsigned long data)
                                           stateName[korg1212->cardState]);
                }
        }
-       spin_unlock(&korg1212->lock);
+       spin_unlock_irqrestore(&korg1212->lock, flags);
 }
 
 static int snd_korg1212_TurnOnIdleMonitor(struct snd_korg1212 *korg1212)
index c387a83..24705d1 100644 (file)
@@ -205,9 +205,10 @@ void snd_emux_timer_callback(unsigned long data)
 {
        struct snd_emux *emu = (struct snd_emux *) data;
        struct snd_emux_voice *vp;
+       unsigned long flags;
        int ch, do_again = 0;
 
-       spin_lock(&emu->voice_lock);
+       spin_lock_irqsave(&emu->voice_lock, flags);
        for (ch = 0; ch < emu->max_voices; ch++) {
                vp = &emu->voices[ch];
                if (vp->state == SNDRV_EMUX_ST_PENDING) {
@@ -225,7 +226,7 @@ void snd_emux_timer_callback(unsigned long data)
                emu->timer_active = 1;
        } else
                emu->timer_active = 0;
-       spin_unlock(&emu->voice_lock);
+       spin_unlock_irqrestore(&emu->voice_lock, flags);
 }
 
 /*