From 9496c252717dfd11d2eb762d0a52df0495996f47 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 4 Apr 2026 14:47:57 -0500 Subject: [PATCH] Add a lock to synchronize DRM master ownership between Qt and SDL --- app/masterhook.c | 19 +++++++++++++++++++ app/masterhook_internal.c | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/app/masterhook.c b/app/masterhook.c index 3d7cb835..fb21793a 100644 --- a/app/masterhook.c +++ b/app/masterhook.c @@ -78,6 +78,9 @@ int g_QtCrtcConnectorCount; bool removeSdlFd(int fd); int takeMasterFromSdlFd(void); +void lockDrmMaster(); +void unlockDrmMaster(); + int drmIsMaster(int fd) { // Detect master by attempting something that requires master. @@ -136,6 +139,9 @@ int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, vo // Call into the real thing int err = fn_drmModePageFlip(fd, crtc_id, fb_id, flags, user_data); if (!g_DisableDrmHooks && err == -EACCES && fd == g_QtDrmMasterFd) { + // Don't allow DRM master ownership to change + lockDrmMaster(); + // If SDL took master from us, try to grab it back temporarily int oldMasterFd = takeMasterFromSdlFd(); drmSetMaster(fd); @@ -144,7 +150,10 @@ int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, vo if (oldMasterFd != -1) { drmSetMaster(oldMasterFd); } + + unlockDrmMaster(); } + return err; } @@ -172,6 +181,9 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, // Call into the real thing int err = fn_drmModeAtomicCommit(fd, req, flags, user_data); if (err == -EACCES && fd == g_QtDrmMasterFd) { + // Don't allow DRM master ownership to change + lockDrmMaster(); + // If SDL took master from us, try to grab it back temporarily int oldMasterFd = takeMasterFromSdlFd(); drmSetMaster(fd); @@ -180,7 +192,10 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, if (oldMasterFd != -1) { drmSetMaster(oldMasterFd); } + + unlockDrmMaster(); } + return err; } @@ -233,6 +248,8 @@ int close(int fd) // If we closed the last SDL FD, restore master to the Qt FD if (ret == 0 && lastSdlFd) { + lockDrmMaster(); + if (drmSetMaster(g_QtDrmMasterFd) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to restore master to Qt DRM FD: %d", @@ -257,6 +274,8 @@ int close(int fd) errno); } } + + unlockDrmMaster(); } return ret; diff --git a/app/masterhook_internal.c b/app/masterhook_internal.c index a8708fcb..b03be56e 100644 --- a/app/masterhook_internal.c +++ b/app/masterhook_internal.c @@ -38,6 +38,21 @@ int g_SdlDrmMasterFds[MAX_SDL_FD_COUNT] = {-1, -1, -1, -1, -1, -1, -1, -1}; int g_SdlDrmMasterFdCount = 0; pthread_mutex_t g_FdTableLock = PTHREAD_MUTEX_INITIALIZER; +// This lock protects sections of code that must run uninterrupted with DRM master +pthread_mutex_t g_MasterLock = PTHREAD_MUTEX_INITIALIZER; + +// Lock order: g_MasterLock -> g_FdTableLock + +void lockDrmMaster() +{ + pthread_mutex_lock(&g_MasterLock); +} + +void unlockDrmMaster() +{ + pthread_mutex_unlock(&g_MasterLock); +} + // Caller must hold g_FdTableLock int getSdlFdEntryIndex(bool unused) { @@ -137,6 +152,9 @@ int openHook(typeof(open) *real_open, typeof(close) *real_close, const char *pat int freeFdIndex; int allocatedFdIndex; + // Prevent other threads from stealing DRM master for now + lockDrmMaster(); + // It is our device. Time to do the magic! pthread_mutex_lock(&g_FdTableLock); @@ -144,6 +162,7 @@ int openHook(typeof(open) *real_open, typeof(close) *real_close, const char *pat freeFdIndex = getSdlFdEntryIndex(true); if (freeFdIndex < 0) { pthread_mutex_unlock(&g_FdTableLock); + unlockDrmMaster(); SDL_assert(freeFdIndex >= 0); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No unused SDL FD table entries!"); @@ -164,6 +183,7 @@ int openHook(typeof(open) *real_open, typeof(close) *real_close, const char *pat // Drop master on Qt's FD so we can pick it up for SDL. if (drmDropMaster(g_QtDrmMasterFd) < 0) { pthread_mutex_unlock(&g_FdTableLock); + unlockDrmMaster(); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to drop master on Qt DRM FD: %d", errno); @@ -195,6 +215,8 @@ int openHook(typeof(open) *real_open, typeof(close) *real_close, const char *pat } pthread_mutex_unlock(&g_FdTableLock); + + unlockDrmMaster(); } } }