Skip to content

Commit 9af832c

Browse files
committed
Fix hang when movie plugins invoke python
Signed-off-by: Roger Nelson <roger.nelson@autodesk.com>
1 parent 1f435df commit 9af832c

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

src/lib/app/RvApp/RvSession.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//
88
#include <RvApp/CommandsModule.h>
9+
#include <Python.h>
910
#include <RvApp/Options.h>
1011
#include <RvApp/RvNodeDefinitions.h>
1112
#include <RvApp/RvSession.h>
@@ -243,6 +244,22 @@ namespace Rv
243244
// new Shader::Function -> initGLSLVersion() -> glGetString
244245
// -> crashes because no context
245246
IPCore::Application::instance()->loadOptionNodeDefinitions();
247+
248+
// Set TwkMovie's blocking callbacks to release (and re-acquire) the Python GIL while it waits for its
249+
// plugins to initialize in separate threads. If any of them need Python, they will try to acquire the
250+
// GIL and deadlock with the main thread.
251+
//
252+
thread_local PyThreadState* preloadGilState = nullptr;
253+
TwkMovie::GenericIO::setBlockingWaitCallbacks([]() { preloadGilState = PyGILState_Check() ? PyEval_SaveThread() : nullptr; },
254+
[]()
255+
{
256+
if (preloadGilState)
257+
{
258+
PyEval_RestoreThread(preloadGilState);
259+
preloadGilState = nullptr;
260+
}
261+
});
262+
246263
firstTime = false;
247264
}
248265

src/lib/image/TwkMovie/MovieIO.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,14 @@ namespace TwkMovie
212212
if (reader->isFinishedLoading())
213213
return;
214214

215+
if (GenericIO::m_onBlockingWaitRelease)
216+
GenericIO::m_onBlockingWaitRelease();
217+
215218
std::unique_lock<std::mutex> lock(m_mainThread_mutex);
216219
m_mainThread_cv.wait(lock, [&reader] { return reader->isFinishedLoading(); });
220+
221+
if (GenericIO::m_onBlockingWaitAcquire)
222+
GenericIO::m_onBlockingWaitAcquire();
217223
}
218224

219225
MovieReader* GenericIO::Preloader::getReader(std::string_view filename, const MovieInfo& info, Movie::ReadRequest& request)
@@ -534,6 +540,14 @@ namespace TwkMovie
534540
bool GenericIO::m_loadedAll = false;
535541
bool GenericIO::m_dnxhdDecodingAllowed = true;
536542
GenericIO::Preloader GenericIO::m_preloader;
543+
GenericIO::WaitCallback GenericIO::m_onBlockingWaitRelease;
544+
GenericIO::WaitCallback GenericIO::m_onBlockingWaitAcquire;
545+
546+
void GenericIO::setBlockingWaitCallbacks(WaitCallback onRelease, WaitCallback onAcquire)
547+
{
548+
m_onBlockingWaitRelease = std::move(onRelease);
549+
m_onBlockingWaitAcquire = std::move(onAcquire);
550+
}
537551

538552
void GenericIO::init()
539553
{

src/lib/image/TwkMovie/TwkMovie/MovieIO.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,21 @@ namespace TwkMovie
413413

414414
static void init();
415415

416+
///
417+
/// Optional callbacks invoked in Preloader::waitForFinishedLoading
418+
/// immediately before and after the blocking condition variable wait.
419+
///
420+
/// Applications that hold resouces they shared with workers (e.g. Python's
421+
/// GIL) should set these to release their lock before the wait and reacquire
422+
/// it afterward, so that background threads can avoid deadlocking the main thread
423+
/// when they access the shared resources.
424+
///
425+
/// Both callbacks default to nullptr (no-op).
426+
///
427+
428+
using WaitCallback = std::function<void()>;
429+
static void setBlockingWaitCallbacks(WaitCallback onRelease, WaitCallback onAcquire);
430+
416431
///
417432
/// Shutdown and free generic movieio plugins.
418433
/// This needs to be called in the application main thread in main.
@@ -539,6 +554,8 @@ namespace TwkMovie
539554
static bool m_loadedAll;
540555
static bool m_dnxhdDecodingAllowed;
541556
static Preloader m_preloader;
557+
static WaitCallback m_onBlockingWaitRelease;
558+
static WaitCallback m_onBlockingWaitAcquire;
542559
};
543560

544561
} // namespace TwkMovie

0 commit comments

Comments
 (0)