pcm direct plugins: drain() call might be blocked when threads are used
authorJaroslav Kysela <perex@perex.cz>
Wed, 3 Mar 2010 09:58:53 +0000 (10:58 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 3 Mar 2010 09:58:53 +0000 (10:58 +0100)
Add SETUP state checks and do modifications according latest ALSA driver
(passing wrong event identification).

ALSA bug#4914

Signed-off-by: Jaroslav Kysela <perex@perex.cz>

src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c

index b648f3a..0a9047d 100644 (file)
@@ -540,7 +540,6 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
 int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix)
 {
        snd_timer_stop(dmix->timer);
-       snd_pcm_direct_clear_timer_queue(dmix);
        return 0;
 }
 
@@ -567,6 +566,7 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in
        switch (snd_pcm_state(dmix->spcm)) {
        case SND_PCM_STATE_XRUN:
        case SND_PCM_STATE_SUSPENDED:
+       case SND_PCM_STATE_SETUP:
                events |= POLLERR;
                break;
        default:
@@ -577,6 +577,7 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in
                        switch (snd_pcm_state(pcm)) {
                        case SND_PCM_STATE_XRUN:
                        case SND_PCM_STATE_SUSPENDED:
+                       case SND_PCM_STATE_SETUP:
                                events |= POLLERR;
                                break;
                        default:
@@ -1126,8 +1127,9 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
        snd_timer_poll_descriptors(dmix->timer, &dmix->timer_fd, 1);
        dmix->poll_fd = dmix->timer_fd.fd;
 
-       dmix->timer_event_suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
-       dmix->timer_event_resume = 1<<SND_TIMER_EVENT_MRESUME;
+       dmix->timer_events = (1<<SND_TIMER_EVENT_MSUSPEND) |
+                            (1<<SND_TIMER_EVENT_MRESUME) |
+                            (1<<SND_TIMER_EVENT_STOP);
 
        /*
         * Some hacks for older kernel drivers
@@ -1146,9 +1148,15 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
                 * suspend/resume events.
                 */
                if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
-                       dmix->timer_event_suspend = 1<<SND_TIMER_EVENT_MPAUSE;
-                       dmix->timer_event_resume = 1<<SND_TIMER_EVENT_MCONTINUE;
+                       dmix->timer_events &= ~((1<<SND_TIMER_EVENT_MSUSPEND) |
+                                               (1<<SND_TIMER_EVENT_MRESUME));
+                       dmix->timer_events |= (1<<SND_TIMER_EVENT_MPAUSE) |
+                                             (1<<SND_TIMER_EVENT_MCONTINUE);
                }
+               /* In older versions, use SND_TIMER_EVENT_START too.
+                */
+               if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 6))
+                       dmix->timer_events |= 1<<SND_TIMER_EVENT_START;
        }
        return 0;
 }
@@ -1275,8 +1283,7 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
        snd_timer_params_set_ticks(params, 1);
        if (dmix->tread) {
                filter = (1<<SND_TIMER_EVENT_TICK) |
-                        dmix->timer_event_suspend |
-                        dmix->timer_event_resume;
+                        dmix->timer_events;
                snd_timer_params_set_filter(params, filter);
        }
        ret = snd_timer_params(dmix->timer, params);
index 006617a..132c281 100644 (file)
@@ -142,10 +142,9 @@ struct snd_pcm_direct {
        int hw_fd;                      /* hardware file descriptor */
        struct pollfd timer_fd;
        int poll_fd;
-       int tread;
-       int timer_need_poll;
-       unsigned int timer_event_suspend;
-       unsigned int timer_event_resume;
+       int tread: 1;
+       int timer_need_poll: 1;
+       unsigned int timer_events;
        int server_fd;
        pid_t server_pid;
        snd_timer_t *timer;             /* timer used as poll_fd */
index 3b791c1..cb62de9 100644 (file)
@@ -605,8 +605,8 @@ static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
        snd_pcm_direct_t *dmix = pcm->private_data;
        if (dmix->state == SND_PCM_STATE_OPEN)
                return -EBADFD;
-       snd_pcm_direct_timer_stop(dmix);
        dmix->state = SND_PCM_STATE_SETUP;
+       snd_pcm_direct_timer_stop(dmix);
        return 0;
 }
 
index c91fa3b..02782a7 100644 (file)
@@ -355,9 +355,9 @@ static int snd_pcm_dshare_drop(snd_pcm_t *pcm)
        snd_pcm_direct_t *dshare = pcm->private_data;
        if (dshare->state == SND_PCM_STATE_OPEN)
                return -EBADFD;
+       dshare->state = SND_PCM_STATE_SETUP;
        snd_pcm_direct_timer_stop(dshare);
        do_silence(pcm);
-       dshare->state = SND_PCM_STATE_SETUP;
        return 0;
 }
 
index 9d42c12..15c727a 100644 (file)
@@ -280,8 +280,8 @@ static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
        snd_pcm_direct_t *dsnoop = pcm->private_data;
        if (dsnoop->state == SND_PCM_STATE_OPEN)
                return -EBADFD;
-       snd_timer_stop(dsnoop->timer);
        dsnoop->state = SND_PCM_STATE_SETUP;
+       snd_timer_stop(dsnoop->timer);
        return 0;
 }