Add a lock to synchronize DRM master ownership between Qt and SDL

This commit is contained in:
Cameron Gutman
2026-04-04 14:47:57 -05:00
parent 6ff3309677
commit 9496c25271
2 changed files with 41 additions and 0 deletions
+19
View File
@@ -78,6 +78,9 @@ int g_QtCrtcConnectorCount;
bool removeSdlFd(int fd); bool removeSdlFd(int fd);
int takeMasterFromSdlFd(void); int takeMasterFromSdlFd(void);
void lockDrmMaster();
void unlockDrmMaster();
int drmIsMaster(int fd) int drmIsMaster(int fd)
{ {
// Detect master by attempting something that requires master. // 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 // Call into the real thing
int err = fn_drmModePageFlip(fd, crtc_id, fb_id, flags, user_data); int err = fn_drmModePageFlip(fd, crtc_id, fb_id, flags, user_data);
if (!g_DisableDrmHooks && err == -EACCES && fd == g_QtDrmMasterFd) { 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 // If SDL took master from us, try to grab it back temporarily
int oldMasterFd = takeMasterFromSdlFd(); int oldMasterFd = takeMasterFromSdlFd();
drmSetMaster(fd); 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) { if (oldMasterFd != -1) {
drmSetMaster(oldMasterFd); drmSetMaster(oldMasterFd);
} }
unlockDrmMaster();
} }
return err; return err;
} }
@@ -172,6 +181,9 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req,
// Call into the real thing // Call into the real thing
int err = fn_drmModeAtomicCommit(fd, req, flags, user_data); int err = fn_drmModeAtomicCommit(fd, req, flags, user_data);
if (err == -EACCES && fd == g_QtDrmMasterFd) { 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 // If SDL took master from us, try to grab it back temporarily
int oldMasterFd = takeMasterFromSdlFd(); int oldMasterFd = takeMasterFromSdlFd();
drmSetMaster(fd); drmSetMaster(fd);
@@ -180,7 +192,10 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req,
if (oldMasterFd != -1) { if (oldMasterFd != -1) {
drmSetMaster(oldMasterFd); drmSetMaster(oldMasterFd);
} }
unlockDrmMaster();
} }
return err; return err;
} }
@@ -233,6 +248,8 @@ int close(int fd)
// If we closed the last SDL FD, restore master to the Qt FD // If we closed the last SDL FD, restore master to the Qt FD
if (ret == 0 && lastSdlFd) { if (ret == 0 && lastSdlFd) {
lockDrmMaster();
if (drmSetMaster(g_QtDrmMasterFd) < 0) { if (drmSetMaster(g_QtDrmMasterFd) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to restore master to Qt DRM FD: %d", "Failed to restore master to Qt DRM FD: %d",
@@ -257,6 +274,8 @@ int close(int fd)
errno); errno);
} }
} }
unlockDrmMaster();
} }
return ret; return ret;
+22
View File
@@ -38,6 +38,21 @@ int g_SdlDrmMasterFds[MAX_SDL_FD_COUNT] = {-1, -1, -1, -1, -1, -1, -1, -1};
int g_SdlDrmMasterFdCount = 0; int g_SdlDrmMasterFdCount = 0;
pthread_mutex_t g_FdTableLock = PTHREAD_MUTEX_INITIALIZER; 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 // Caller must hold g_FdTableLock
int getSdlFdEntryIndex(bool unused) int getSdlFdEntryIndex(bool unused)
{ {
@@ -137,6 +152,9 @@ int openHook(typeof(open) *real_open, typeof(close) *real_close, const char *pat
int freeFdIndex; int freeFdIndex;
int allocatedFdIndex; int allocatedFdIndex;
// Prevent other threads from stealing DRM master for now
lockDrmMaster();
// It is our device. Time to do the magic! // It is our device. Time to do the magic!
pthread_mutex_lock(&g_FdTableLock); 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); freeFdIndex = getSdlFdEntryIndex(true);
if (freeFdIndex < 0) { if (freeFdIndex < 0) {
pthread_mutex_unlock(&g_FdTableLock); pthread_mutex_unlock(&g_FdTableLock);
unlockDrmMaster();
SDL_assert(freeFdIndex >= 0); SDL_assert(freeFdIndex >= 0);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"No unused SDL FD table entries!"); "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. // Drop master on Qt's FD so we can pick it up for SDL.
if (drmDropMaster(g_QtDrmMasterFd) < 0) { if (drmDropMaster(g_QtDrmMasterFd) < 0) {
pthread_mutex_unlock(&g_FdTableLock); pthread_mutex_unlock(&g_FdTableLock);
unlockDrmMaster();
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to drop master on Qt DRM FD: %d", "Failed to drop master on Qt DRM FD: %d",
errno); errno);
@@ -195,6 +215,8 @@ int openHook(typeof(open) *real_open, typeof(close) *real_close, const char *pat
} }
pthread_mutex_unlock(&g_FdTableLock); pthread_mutex_unlock(&g_FdTableLock);
unlockDrmMaster();
} }
} }
} }