fix: fix audio Mixer freeze

This commit is contained in:
2026-05-25 11:35:03 +02:00
parent 96943116f8
commit 29d5daaa62
+31 -2
View File
@@ -383,17 +383,36 @@ namespace Drivers::Audio::Mixer {
g_lock.Acquire();
VirtualStream& s = g_streams[handle];
bool changed = false;
// Pull the ring pointer out of the slot before freeing it. Once
// s.active=false and s.ring=nullptr are visible under the lock no
// other path can reach this pointer, so the actual PFA free can run
// with the lock released — keeping the HDA buffer-complete IRQ from
// spinning on g_lock while ReallocConsecutive walks the free list.
int16_t* ringToFree = nullptr;
bool lastStream = false;
if (s.active) {
FreeRing(s.ring);
ringToFree = s.ring;
s.ring = nullptr;
s.active = false;
s.ownerPid = 0;
s.name[0] = '\0';
if (g_activeCount > 0) g_activeCount--;
lastStream = (g_activeCount == 0);
BumpSerialLocked();
changed = true;
}
// Quiesce the hardware when the final virtual stream goes away so
// the HDA DMA ring stops looping its last 32 KiB of samples. The
// next Open() reopens the HDA stream via EnsureHdaOpen().
bool closeHda = lastStream && g_hdaOpened;
int hdaHandle = g_hdaHandle;
if (closeHda) {
g_hdaOpened = false;
g_hdaHandle = -1;
}
g_lock.Release();
if (closeHda) IntelHda::Close(hdaHandle);
if (ringToFree) FreeRing(ringToFree);
if (changed) Sched::WakeObjectWaiters((void*)&g_serial);
}
@@ -495,12 +514,14 @@ namespace Drivers::Audio::Mixer {
}
void CleanupProcess(int pid) {
int16_t* ringsToFree[MAX_STREAMS] = {};
int ringCount = 0;
g_lock.Acquire();
bool changed = false;
for (int i = 0; i < MAX_STREAMS; i++) {
VirtualStream& s = g_streams[i];
if (s.active && s.ownerPid == pid) {
FreeRing(s.ring);
ringsToFree[ringCount++] = s.ring;
s.ring = nullptr;
s.active = false;
s.ownerPid = 0;
@@ -509,8 +530,16 @@ namespace Drivers::Audio::Mixer {
changed = true;
}
}
bool closeHda = changed && (g_activeCount == 0) && g_hdaOpened;
int hdaHandle = g_hdaHandle;
if (closeHda) {
g_hdaOpened = false;
g_hdaHandle = -1;
}
if (changed) BumpSerialLocked();
g_lock.Release();
if (closeHda) IntelHda::Close(hdaHandle);
for (int i = 0; i < ringCount; i++) FreeRing(ringsToFree[i]);
if (changed) Sched::WakeObjectWaiters((void*)&g_serial);
}