Hot-unplugging a sound device, such as a USB sound card, whilst being
consumed by an application, results in the parent bus going into anan infinite loop until either the
infinite loop (and as a result, becoming unusable) until either the
application closes the device's file descriptor, or the channel
automatically times out after hw.snd.timeout seconds. In the case of a
detach however, the timeout approach is still not ideal, since we want
all resources to be released immediatelly, without waiting for N seconds
until we can use the bus again.
The timeout mechanism works by calling chn_sleep() in chn_read() and
chn_write() (see pcm/channel.c) in order to send the thread to sleep,
using cv_timedwait_sig(). Since chn_sleep() sets the CHN_F_SLEEPING flag
while waiting for cv_timedwait_sig() to return, we can test this flag in
pcm_unregister() (called during detach) and wakeup the sleeping
thread(s) to immediately kill the channel(s) being consumed.
To avoid a use-after-free bug when destroyingsleeping until all clones and/or the clone(s) (as a resultmixer have been unref'd,
of destroying them before the sleeping threads have drained)in case an application refuses to close the descriptor, blockwe use
pcm_unregister() using snd_clone_sleep() until the clone refcountdestroy_dev_sched_cb() instead of destroy_dev(). This way the device can
reaches 0detach (and re-attach) asynchronously, at which pointleaving the thread will be woken up bydevfs node(s) in an
snd_clone_wakeup() and pcm_unregister() will resume execution.
While here, remove snddev_info's inprog field, as well as pcm_inprog(),orphan state waiting for clean up when the application releases the
as they are no longer useddescriptor.
Sponsored by: The FreeBSD Foundation
MFC after: 3 weeks
PR: 194727