From c902543ae450c6318508c03d58c4a35e6ac6af47 Mon Sep 17 00:00:00 2001 From: tux3 Date: Sun, 25 Oct 2015 00:17:22 +0200 Subject: [PATCH] Fix call race leading to deadlock and memory leak A call cancel/accepted race was locking up both UI and AV threads, while the stream thread was shoveling more and more video frames on the AV thread's event queue --- src/core/coreav.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index 365eba2a1..2d686cc16 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -504,6 +504,9 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi // Run this slow path callback asynchronously on the AV thread to avoid deadlocks if (QThread::currentThread() != self->coreavThread.get()) { + // We assume the original caller doesn't come from the CoreAV thread here + while (self->threadSwitchLock.test_and_set(std::memory_order_acquire)) + QThread::yieldCurrentThread(); // Shouldn't spin for long, we have priority return (void)QMetaObject::invokeMethod(self, "stateCallback", Qt::QueuedConnection, Q_ARG(ToxAV*, toxav), Q_ARG(uint32_t, friendNum), Q_ARG(uint32_t, state), Q_ARG(void*, _self)); @@ -512,6 +515,7 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi if(!self->calls.contains(friendNum)) { qWarning() << QString("stateCallback called, but call %1 is already dead").arg(friendNum); + self->threadSwitchLock.clear(std::memory_order_release); return; } ToxFriendCall& call = self->calls[friendNum]; @@ -554,6 +558,7 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi call.state = static_cast(state); } + self->threadSwitchLock.clear(std::memory_order_release); } void CoreAV::bitrateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t arate, uint32_t vrate, void *_self)