mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	More fixes for 100% CPU hang with dmix
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.
This commit is contained in:
		
							parent
							
								
									e5b91844bf
								
							
						
					
					
						commit
						aa89f27de4
					
				
					 3 changed files with 43 additions and 17 deletions
				
			
		| 
						 | 
					@ -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);
 | 
						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)
 | 
					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;
 | 
						snd_pcm_direct_t *dmix = pcm->private_data;
 | 
				
			||||||
	unsigned short events;
 | 
						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);
 | 
						assert(pfds && nfds == 1 && revents);
 | 
				
			||||||
	events = pfds[0].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 {
 | 
							} else {
 | 
				
			||||||
			empty = snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min;
 | 
								empty = snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* empty the timer read queue */
 | 
							if (empty)
 | 
				
			||||||
		while (empty && snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ;
 | 
								snd_pcm_direct_clear_timer_queue(dmix);
 | 
				
			||||||
		if (empty)
 | 
							if (empty)
 | 
				
			||||||
			events &= ~(POLLOUT|POLLIN);
 | 
								events &= ~(POLLOUT|POLLIN);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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_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_mmap(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_direct_munmap(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);
 | 
					int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
 | 
				
			||||||
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
 | 
					struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
						diff = slave_hw_ptr - old_slave_hw_ptr;
 | 
				
			||||||
	if (diff == 0)		/* fast path */
 | 
						if (diff == 0)		/* fast path */
 | 
				
			||||||
		return 0;
 | 
							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) {
 | 
						if (diff < 0) {
 | 
				
			||||||
		slave_hw_ptr += dmix->shmptr->s.boundary;
 | 
							slave_hw_ptr += dmix->shmptr->s.boundary;
 | 
				
			||||||
		diff = slave_hw_ptr - old_slave_hw_ptr;
 | 
							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;
 | 
							return 0;
 | 
				
			||||||
	if ((avail = snd_pcm_mmap_playback_avail(pcm)) >= pcm->stop_threshold) {
 | 
						if ((avail = snd_pcm_mmap_playback_avail(pcm)) >= pcm->stop_threshold) {
 | 
				
			||||||
		struct timeval tv;
 | 
							struct timeval tv;
 | 
				
			||||||
		snd_timer_stop(dmix->timer);
 | 
							snd_pcm_direct_timer_stop(dmix);
 | 
				
			||||||
		gettimeofday(&tv, 0);
 | 
							gettimeofday(&tv, 0);
 | 
				
			||||||
		dmix->trigger_tstamp.tv_sec = tv.tv_sec;
 | 
							dmix->trigger_tstamp.tv_sec = tv.tv_sec;
 | 
				
			||||||
		dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
 | 
							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;
 | 
						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)
 | 
					static int snd_pcm_dmix_start(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_direct_t *dmix = pcm->private_data;
 | 
						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)
 | 
						if (dmix->state != SND_PCM_STATE_PREPARED)
 | 
				
			||||||
		return -EBADFD;
 | 
							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);
 | 
						avail = snd_pcm_mmap_playback_hw_avail(pcm);
 | 
				
			||||||
	if (avail == 0)
 | 
						if (avail == 0)
 | 
				
			||||||
		dmix->state = STATE_RUN_PENDING;
 | 
							dmix->state = STATE_RUN_PENDING;
 | 
				
			||||||
| 
						 | 
					@ -438,10 +453,8 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm)
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		if (avail > (snd_pcm_sframes_t)pcm->buffer_size)
 | 
							if (avail > (snd_pcm_sframes_t)pcm->buffer_size)
 | 
				
			||||||
			avail = pcm->buffer_size;
 | 
								avail = pcm->buffer_size;
 | 
				
			||||||
		err = snd_timer_start(dmix->timer);
 | 
							if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
		dmix->state = SND_PCM_STATE_RUNNING;
 | 
					 | 
				
			||||||
		snd_pcm_dmix_sync_area(pcm, avail);
 | 
							snd_pcm_dmix_sync_area(pcm, avail);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	gettimeofday(&tv, 0);
 | 
						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;
 | 
						snd_pcm_direct_t *dmix = pcm->private_data;
 | 
				
			||||||
	if (dmix->state == SND_PCM_STATE_OPEN)
 | 
						if (dmix->state == SND_PCM_STATE_OPEN)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	snd_timer_stop(dmix->timer);
 | 
						snd_pcm_direct_timer_stop(dmix);
 | 
				
			||||||
	dmix->state = SND_PCM_STATE_SETUP;
 | 
						dmix->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
	return 0;
 | 
						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;
 | 
						snd_pcm_direct_t *dmix = pcm->private_data;
 | 
				
			||||||
        if (enable) {
 | 
					        if (enable) {
 | 
				
			||||||
		if (dmix->state == SND_PCM_STATE_RUNNING)
 | 
							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)
 | 
							else if (dmix->state != STATE_RUN_PENDING)
 | 
				
			||||||
			return -EBADFD;
 | 
								return -EBADFD;
 | 
				
			||||||
		dmix->state = SND_PCM_STATE_PAUSED;
 | 
							dmix->state = SND_PCM_STATE_PAUSED;
 | 
				
			||||||
| 
						 | 
					@ -500,6 +513,7 @@ static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable)
 | 
				
			||||||
			return -EBADFD;
 | 
								return -EBADFD;
 | 
				
			||||||
		if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) {
 | 
							if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) {
 | 
				
			||||||
			dmix->state = SND_PCM_STATE_RUNNING;
 | 
								dmix->state = SND_PCM_STATE_RUNNING;
 | 
				
			||||||
 | 
								/* FIXME: sync the hwptr */
 | 
				
			||||||
			snd_timer_start(dmix->timer);
 | 
								snd_timer_start(dmix->timer);
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			dmix->state = STATE_RUN_PENDING;
 | 
								dmix->state = STATE_RUN_PENDING;
 | 
				
			||||||
| 
						 | 
					@ -589,13 +603,11 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	snd_pcm_mmap_appl_forward(pcm, size);
 | 
					 | 
				
			||||||
	if (dmix->state == STATE_RUN_PENDING) {
 | 
						if (dmix->state == STATE_RUN_PENDING) {
 | 
				
			||||||
		err = snd_timer_start(dmix->timer);
 | 
							if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
		dmix->state = SND_PCM_STATE_RUNNING;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						snd_pcm_mmap_appl_forward(pcm, size);
 | 
				
			||||||
	if (dmix->state == SND_PCM_STATE_RUNNING) {
 | 
						if (dmix->state == SND_PCM_STATE_RUNNING) {
 | 
				
			||||||
		err = snd_pcm_dmix_sync_ptr(pcm);
 | 
							err = snd_pcm_dmix_sync_ptr(pcm);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue