diff --git a/docs/changelog.rst b/docs/changelog.rst index 3ee3dee12..31a098624 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -41,6 +41,8 @@ To update |kitty|, :doc:`follow the instructions `. - Linux: Use the system "bell" sound for the terminal bell. Adds libcanberra as a new dependency to play the system sound. +- macOS: Fix a rare deadlock causing kitty to hang (:iss:`1779`) + 0.14.2 [2019-06-09] --------------------- diff --git a/glfw/cocoa_init.m b/glfw/cocoa_init.m index e39559ecb..d82e3f7e0 100644 --- a/glfw/cocoa_init.m +++ b/glfw/cocoa_init.m @@ -399,7 +399,6 @@ int _glfwPlatformInit(void) if (!initializeTIS()) return false; - _glfw.ns.displayLinks.lock = [NSLock new]; _glfwInitTimerNS(); _glfwInitJoysticksNS(); @@ -413,11 +412,7 @@ void _glfwPlatformTerminate(void) { @autoreleasepool { - if (_glfw.ns.displayLinks.lock) { - _glfwClearDisplayLinks(); - [_glfw.ns.displayLinks.lock release]; - _glfw.ns.displayLinks.lock = nil; - } + _glfwClearDisplayLinks(); if (_glfw.ns.inputSource) { diff --git a/glfw/cocoa_monitor.m b/glfw/cocoa_monitor.m index 3ddde7002..485ff097e 100644 --- a/glfw/cocoa_monitor.m +++ b/glfw/cocoa_monitor.m @@ -243,16 +243,15 @@ bool refreshMonitorScreen(_GLFWmonitor* monitor) ////////////////////////////////////////////////////////////////////////// void _glfwClearDisplayLinks() { - [_glfw.ns.displayLinks.lock lock]; for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) { if (_glfw.ns.displayLinks.entries[i].displayLink) { CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink); CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink); _glfw.ns.displayLinks.entries[i].displayLink = nil; + _glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0; } } _glfw.ns.displayLinks.count = 0; - [_glfw.ns.displayLinks.lock unlock]; } static CVReturn displayLinkCallback( @@ -261,28 +260,13 @@ static CVReturn displayLinkCallback( CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo) { CGDirectDisplayID displayID = (CGDirectDisplayID)userInfo; - [_glfw.ns.displayLinks.lock lock]; - bool notify = false; - for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) { - if (_glfw.ns.displayLinks.entries[i].displayID == displayID) { - if (_glfw.ns.displayLinks.entries[i].renderFrameRequested) { - notify = true; - _glfw.ns.displayLinks.entries[i].renderFrameRequested = false; - } - break; - } - } - [_glfw.ns.displayLinks.lock unlock]; - if (notify) { - NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID]; - [NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO]; - [arg release]; - } + NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID]; + [NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO]; + [arg release]; return kCVReturnSuccess; } static inline void createDisplayLink(CGDirectDisplayID displayID) { - [_glfw.ns.displayLinks.lock lock]; if (_glfw.ns.displayLinks.count >= sizeof(_glfw.ns.displayLinks.entries)/sizeof(_glfw.ns.displayLinks.entries[0]) - 1) return; for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) { if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return; @@ -292,7 +276,6 @@ static inline void createDisplayLink(CGDirectDisplayID displayID) { entry->displayID = displayID; CVDisplayLinkCreateWithCGDisplay(displayID, &entry->displayLink); CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)displayID); - [_glfw.ns.displayLinks.lock unlock]; } // Poll for changes in the set of connected monitors diff --git a/glfw/cocoa_platform.h b/glfw/cocoa_platform.h index 3f7f8b6dd..62960d746 100644 --- a/glfw/cocoa_platform.h +++ b/glfw/cocoa_platform.h @@ -144,7 +144,7 @@ typedef struct _GLFWDisplayLinkNS { CVDisplayLinkRef displayLink; CGDirectDisplayID displayID; - bool renderFrameRequested; + double lastRenderFrameRequestedAt; } _GLFWDisplayLinkNS; // Cocoa-specific global data @@ -183,7 +183,6 @@ typedef struct _GLFWlibraryNS struct { _GLFWDisplayLinkNS entries[256]; size_t count; - id lock; } displayLinks; } _GLFWlibraryNS; diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index b58a45529..688ce57bd 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -67,13 +67,12 @@ static unsigned long long display_link_shutdown_timer = 0; void _glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) { - [_glfw.ns.displayLinks.lock lock]; display_link_shutdown_timer = 0; for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) { _GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i]; if (dl->displayLink) CVDisplayLinkStop(dl->displayLink); + dl->lastRenderFrameRequestedAt = 0; } - [_glfw.ns.displayLinks.lock unlock]; } static inline void @@ -86,23 +85,26 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) { w->ns.renderFrameCallback = callback; w->ns.renderFrameRequested = true; CGDirectDisplayID displayID = displayIDForWindow(w); - [_glfw.ns.displayLinks.lock lock]; if (display_link_shutdown_timer) { _glfwPlatformUpdateTimer(display_link_shutdown_timer, DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, true); } else { display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL); } + double now = glfwGetTime(); for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) { _GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i]; if (dl->displayID == displayID) { - dl->renderFrameRequested = true; + dl->lastRenderFrameRequestedAt = now; if (!CVDisplayLinkIsRunning(dl->displayLink)) { CVDisplayLinkStart(dl->displayLink); + } else { + if (dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt) { + if (dl->displayLink) CVDisplayLinkStop(dl->displayLink); + dl->lastRenderFrameRequestedAt = 0; + } } - break; } } - [_glfw.ns.displayLinks.lock unlock]; } void