Fix guest sound playback XRUN issue

CU
2d ago
+482-180

Fix guest OS sound playback XRUN (underrun, specifically) issue.

As using a concurrent queue with conditional variables holding PCM
frames, apply the famous self pipe trick so that the emulator can
safely handle asynchronous signals when virtio-snd is enabled.

Test Procedures

  1. Set these parameters to =y in the Linux Kernel config:
CONFIG_SND_PCM_XRUN_DEBUG=y
CONFIG_SND_VERBOSE_PROCFS=y
CONFIG_SND_DEBUG=y
  1. Remove the existing config using rm linux/.config.
  2. Compile the Linux Kernel with ./scripts/build-image.sh --linux.
  3. Run make check to run emulated guest OS.
  4. After login into guest OS, run echo 3 > /proc/asound/card0/pcmp0/xrun_debug.
  5. Run aplay /usr/share/sounds/alsa/Front_Center.wav three times in guest OS.
  6. In guest OS, run dmesg.

Expected Results

  • The dmesg should not produce any XRUN messages, for example:
# dmesg
...
[   65.908925] ALSA: PCM: [Q] Lost interrupts?: (stream=1, delta=4000, new_hw_ptr=4000, old_hw_ptr=0)           
[   65.913926] CPU: 0 UID: 0 PID: 10 Comm: kworker/0:1 Not tainted 6.12.61 #1                                   
[   65.914926] Hardware name: semu (DT)                                                                         
[   65.914926] Workqueue: events virtsnd_pcm_period_elapsed                                                     
[   65.915927] Call Trace:                                                                                      
[   65.915927] [<c0004aa4>] dump_backtrace+0x2c/0x3c                                                            
[   65.916927] [<c0419a74>] show_stack+0x40/0x54                                                                
[   65.918927] [<c041f3d0>] dump_stack_lvl+0x74/0xa8                                                            
[   65.919928] [<c041f420>] dump_stack+0x1c/0x2c                                                                
[   65.920928] [<c030693c>] snd_pcm_update_hw_ptr0+0x46c/0x540                                                  
[   65.921928] [<c0306a7c>] snd_pcm_period_elapsed_under_stream_lock+0x6c/0x9c                                  
[   65.923929] [<c0306ae0>] snd_pcm_period_elapsed+0x34/0x54                                                    
[   65.924929] [<c030bc28>] virtsnd_pcm_period_elapsed+0x18/0x28                                                
[   65.926929] [<c0027760>] process_scheduled_works+0x1dc/0x2a4
[   65.927930] [<c0027d74>] worker_thread+0x170/0x208
[   65.928930] [<c002ff4c>] kthread+0xe0/0xe4
[   65.929930] [<c04276c8>] ret_from_exception_end+0x14/0x20

Summary by cubic

Fixes guest audio playback XRUNs and the dropped final period by unblocking the emulator event loop on TX used-ring updates, honoring the guest's period size, and draining PortAudio buffers before stop.

  • Enables the emulator self-pipe for VIRTIOSND, with wake-pipe creation decoupled from the window backend for ENABLE_SDL=0 builds.
  • Updates the used-ring per element and validates PCM parameters in set-params and prepare, computing period frames from the guest's period_bytes.
  • Clears the releasing flag on START, records START only after Pa_StartStream succeeds, and blocks STOP until PortAudio drains on a wait capped at one period plus slack (minimum 2s).
  • Uses tx_busy and virtio_snd_tx_done so STOP, PREPARE, and RELEASE wait for both in-flight TX submissions and queued buffers; enqueue failures now report VIRTIO_SND_S_IO_ERR.
  • Allocates the device state and starts the TX worker before PortAudio init so headless audio failures leave MMIO state intact; guards vsnd->priv in status updates and register access.
  • Joins the TX thread and terminates PortAudio in virtio_snd_cleanup, closing wake_fd[1] before wake_fd[0], and removes the buffer-size workaround from README.md.