alsa-lib
alsa-lib copied to clipboard
snd_pcm_wait_nocheck - use more finer timeout for the the poll wait
Axfer calls polling system call(i.e. poll(2), epoll(7), select(7)) without explicit timeout when running for IRQ-based scheduling model. In a case that driver achieves to control sound hardware for periodical hardware IRQ, the call can return due to any event queued by the driver in hardware IRQ context. However, in a case that driver fails to control it, the call cannot return.
Especially, this situation easily occurs when developers work to support hardware newly. It's better to care for the situation.
How to reproduce:
- prepare sound hardware which driver fail to control for periodical hardware IRQ.
- execute axfer for the driver/hardware with options to:
- use IRQ-based scheduling model:
--sched-model=irq - use polling system call: without
--test-nowait
- the running process blocks as a call of polling system call (defaultly poll(2) by snd_pcm_wait())
I filed PR alsa-project/alsa-utils#31 .
However, even if merging the patchset, poll(2) system call is called without timeout inner alsa-lib. This occurs in cases that some alsa-lib PCM plugins (e.g. plug) is used which call below alsa-lib APIs internally:
- snd_pcm_read_areas()
- snd_pcm_write_areas()
These two APIs call poll(2) internally without explicit timeout (-1). Furthermore, even if returning due to emitted signal (errno = EINTR), poll(2) is called again in internal loop. This disables users to terminate runtime by SIGINT.
->snd_pcm_readi()
= snd_pcm_plugin_read1()
->snd_pcm_read_areas()
->__snd_pcm_wait_in_lock(timeout=-1)
->snd_pcm_wait_nocheck(timeout=-1)
->snd_pcm_readn()
= snd_pcm_plugin_read1()
->snd_pcm_read_areas()
->__snd_pcm_wait_in_lock(timeout=-1)
->snd_pcm_wait_nocheck(timeout=-1)
->snd_pcm_writei()
= snd_pcm_plugin_write1()
->snd_pcm_write_areas()
->snd_pcm_wait_nocheck(timeout=-1)
->snd_pcm_writen()
= snd_pcm_plugin_write1()
->snd_pcm_write_areas()
->snd_pcm_wait_nocheck(timeout=-1)
int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout)
{
int err_poll;
...
do {
__snd_pcm_unlock(pcm);
err_poll = poll(pfd, npfds, timeout);
__snd_pcm_lock(pcm);
if (err_poll < 0) {
if (errno == EINTR && !PCMINABORT(pcm))
continue;
return -errno;
}
if (!err_poll)
break;
...
} while (!(revents & (POLLIN | POLLOUT)));
...
}
The maximal timeout can be estimated for those callers wait callers. I agree that the timeout should be set to a more sane value, because we know the stream parameters (thus the real time timing).