]> git.alsa-project.org Git - alsa-lib.git/commitdiff
More fixes for 100% CPU hang with dmix
authorTakashi Iwai <tiwai@suse.de>
Tue, 5 Apr 2005 15:50:15 +0000 (15:50 +0000)
committerTakashi Iwai <tiwai@suse.de>
Tue, 5 Apr 2005 15:50:15 +0000 (15:50 +0000)
More fixes for 100% CPU hang-up problem with dmix.

- Clear timer queues properly when XRUN happens.
- Don't check XRUN when the stream isn't really running.
- Do hwsync properly for the delayed start state.

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

index f249e1957c645ff772dcf24cfa24157cc7f5e17f..7b54654043d9f8fe01a3047c60d9618ea3aa372a 100644 (file)
@@ -415,13 +415,26 @@ int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid)
        return snd_timer_async(dmix->timer, sig, pid);
 }
 
+/* empty the timer read queue */
+static void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
+{
+       /* rbuf might be overwriten by multiple plugins */
+       /* we don't need the value */
+       snd_timer_tread_t rbuf;
+       while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf))
+               ;
+}
+
+int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix)
+{
+       snd_timer_stop(dmix->timer);
+       snd_pcm_direct_clear_timer_queue(dmix);
+}
+
 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
 {
        snd_pcm_direct_t *dmix = pcm->private_data;
        unsigned short events;
-       /* rbuf might be overwriten by multiple plugins */
-       /* we don't need the value */
-       static snd_timer_tread_t rbuf;
 
        assert(pfds && nfds == 1 && revents);
        events = pfds[0].revents;
@@ -435,8 +448,8 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in
                } else {
                        empty = snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min;
                }
-               /* empty the timer read queue */
-               while (empty && snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ;
+               if (empty)
+                       snd_pcm_direct_clear_timer_queue(dmix);
                if (empty)
                        events &= ~(POLLOUT|POLLIN);
        }
index 1ccefa5b44b4d98618813c342f6005bc98232078..706e86b8fdafcafa349089b5c709caf4008b2939 100644 (file)
@@ -144,6 +144,7 @@ int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
 int snd_pcm_direct_mmap(snd_pcm_t *pcm);
 int snd_pcm_direct_munmap(snd_pcm_t *pcm);
+int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
 
 int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
index 2e1caf059a37d13b64dec8d5fa4809310f222702..e0979638109ff5790010dd2e268fb88f8b387eea 100644 (file)
@@ -270,6 +270,10 @@ static int _snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, int do_slave_sync)
        diff = slave_hw_ptr - old_slave_hw_ptr;
        if (diff == 0)          /* fast path */
                return 0;
+       if (dmix->state != SNDRV_PCM_STATE_RUNNING &&
+           dmix->state != SNDRV_PCM_STATE_DRAINING)
+               /* not really started yet - don't update hw_ptr */
+               return 0;
        if (diff < 0) {
                slave_hw_ptr += dmix->shmptr->s.boundary;
                diff = slave_hw_ptr - old_slave_hw_ptr;
@@ -280,7 +284,7 @@ static int _snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, int do_slave_sync)
                return 0;
        if ((avail = snd_pcm_mmap_playback_avail(pcm)) >= pcm->stop_threshold) {
                struct timeval tv;
-               snd_timer_stop(dmix->timer);
+               snd_pcm_direct_timer_stop(dmix);
                gettimeofday(&tv, 0);
                dmix->trigger_tstamp.tv_sec = tv.tv_sec;
                dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
@@ -419,6 +423,19 @@ static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
        return 0;
 }
 
+static int snd_pcm_dmix_start_timer(snd_pcm_direct_t *dmix)
+{
+       int err;
+
+       snd_pcm_hwsync(dmix->spcm);
+       dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
+       err = snd_timer_start(dmix->timer);
+       if (err < 0)
+               return err;
+       dmix->state = SND_PCM_STATE_RUNNING;
+       return 0;
+}
+
 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
 {
        snd_pcm_direct_t *dmix = pcm->private_data;
@@ -428,8 +445,6 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm)
        
        if (dmix->state != SND_PCM_STATE_PREPARED)
                return -EBADFD;
-       snd_pcm_hwsync(dmix->spcm);
-       dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
        avail = snd_pcm_mmap_playback_hw_avail(pcm);
        if (avail == 0)
                dmix->state = STATE_RUN_PENDING;
@@ -438,10 +453,8 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm)
        else {
                if (avail > (snd_pcm_sframes_t)pcm->buffer_size)
                        avail = pcm->buffer_size;
-               err = snd_timer_start(dmix->timer);
-               if (err < 0)
+               if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
                        return err;
-               dmix->state = SND_PCM_STATE_RUNNING;
                snd_pcm_dmix_sync_area(pcm, avail);
        }
        gettimeofday(&tv, 0);
@@ -455,7 +468,7 @@ 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_timer_stop(dmix->timer);
+       snd_pcm_direct_timer_stop(dmix);
        dmix->state = SND_PCM_STATE_SETUP;
        return 0;
 }
@@ -491,7 +504,7 @@ static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable)
        snd_pcm_direct_t *dmix = pcm->private_data;
         if (enable) {
                if (dmix->state == SND_PCM_STATE_RUNNING)
-                       snd_timer_stop(dmix->timer);
+                       snd_pcm_direct_timer_stop(dmix);
                else if (dmix->state != STATE_RUN_PENDING)
                        return -EBADFD;
                dmix->state = SND_PCM_STATE_PAUSED;
@@ -500,6 +513,7 @@ static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable)
                        return -EBADFD;
                if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) {
                        dmix->state = SND_PCM_STATE_RUNNING;
+                       /* FIXME: sync the hwptr */
                        snd_timer_start(dmix->timer);
                } else
                        dmix->state = STATE_RUN_PENDING;
@@ -589,13 +603,11 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
        default:
                break;
        }
-       snd_pcm_mmap_appl_forward(pcm, size);
        if (dmix->state == STATE_RUN_PENDING) {
-               err = snd_timer_start(dmix->timer);
-               if (err < 0)
+               if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
                        return err;
-               dmix->state = SND_PCM_STATE_RUNNING;
        }
+       snd_pcm_mmap_appl_forward(pcm, size);
        if (dmix->state == SND_PCM_STATE_RUNNING) {
                err = snd_pcm_dmix_sync_ptr(pcm);
                if (err < 0)