void StimulusDisplay::stateSystemCallback(const Datum &data, MWorksTime time) { unique_lock lock(display_lock); int newState = data.getInteger(); if ((IDLE == newState) && displayLinksRunning) { // If another thread is waiting for a display refresh, allow it to complete before stopping // the display link while (waitingForRefresh) { refreshCond.wait(lock); } displayLinksRunning = false; currentOutputTimeUS = -1; // We need to release the lock before calling CVDisplayLinkStop, because // StimulusDisplay::displayLinkCallback could be blocked waiting for the lock, and // CVDisplayLinkStop won't return until displayLinkCallback exits, leading to deadlock. lock.unlock(); // NOTE: As of OS X 10.11, stopping the display links from a non-main thread causes issues dispatch_sync(dispatch_get_main_queue(), ^{ for (auto dl : displayLinks) { if (kCVReturnSuccess != CVDisplayLinkStop(dl)) { merror(M_DISPLAY_MESSAGE_DOMAIN, "Unable to stop updates on display %d", CVDisplayLinkGetCurrentCGDisplay(dl)); } } }); mprintf(M_DISPLAY_MESSAGE_DOMAIN, "Display updates stopped"); } else if ((RUNNING == newState) && !displayLinksRunning) {
void StimulusDisplay::stateSystemCallback(const Datum &data, MWorksTime time) { unique_lock lock(display_lock); int newState = data.getInteger(); if (IDLE == newState) { if (CVDisplayLinkIsRunning(displayLink)) { // If another thread is waiting for a display refresh, allow it to complete before stopping // the display link while (waitingForRefresh) { refreshCond.wait(lock); } // We need to release the lock before calling CVDisplayLinkStop, because // StimulusDisplay::displayLinkCallback could be blocked waiting for the lock, and // CVDisplayLinkStop won't return until displayLinkCallback exits, leading to deadlock. lock.unlock(); if (kCVReturnSuccess != CVDisplayLinkStop(displayLink)) { merror(M_DISPLAY_MESSAGE_DOMAIN, "Unable to stop display updates"); } else { currentOutputTimeUS = -1; mprintf(M_DISPLAY_MESSAGE_DOMAIN, "Display updates stopped"); } } } else if (RUNNING == newState) { if (!CVDisplayLinkIsRunning(displayLink)) { lastFrameTime = 0; if (kCVReturnSuccess != CVDisplayLinkStart(displayLink)) { merror(M_DISPLAY_MESSAGE_DOMAIN, "Unable to start display updates"); } else { // Wait for a refresh to complete, so we know that getCurrentOutputTimeUS() will return a valid time ensureRefresh(lock); mprintf(M_DISPLAY_MESSAGE_DOMAIN, "Display updates started (main = %d, current = %d)", CGMainDisplayID(), CVDisplayLinkGetCurrentCGDisplay(displayLink)); } } } }