I can't find any Apple docs saying anything like "invoke this only on the Appkit thread", perhaps because you don't have to, but nor do I see any caution about using a consistent thread.

The JDK code to start a thread is
- (void) startDisplayLink {
    if (!CVDisplayLinkIsRunning(self.displayLink)) {
        CVDisplayLinkStart(self.displayLink);
        J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_startDisplayLink");
    }
    displayLinkCount += KEEP_ALIVE_INC; // Keep alive displaylink counter
}

and I can see how at least in theory two threads could be calling this code at the same time and so start two threads. Although I'm a bit surprised if macOS doesn't detect this internally and reject it and return an error. And we aren't checking for error returns, but in the case of an
error return, I'd really expect that to mean it did not start the thread.

You could try enabling java2d logging to see if we at least have matching numbers of calls to start & stop. But I can imagine that if we've overwritten a field holding is the display link thread reference
that CVDisplayLinkStop can't stop that leaked thread.

A relatively simple experiment, that doesn't need JDK would be to just call CVDisplayLinkStart N times, checking return value and then call CVDisplayLinkStop N times (again checking return value,
and at the end of it see how many threads are running.

Probably that will tell us we do need to run all these calls on one of those 3 threads (AppKit, EDT, QueueFlusher), although I'm not sure what implementation and performance consequences might ensue.

You should file a bug with as much info as you can gather.

-phil.

On 10/8/23 6:52 AM, Alan Snyder wrote:
I’ve been investigating a problem with a long running application that 
accumulates an apparently unbounded number of
CVDisplayLink threads. I do not yet have an explanation or a test case.

The code that creates and releases CVDisplayLinks looks fine, but that assumes 
there are no threading issues.
It looks like there are threading issues.

Specifically, it appears that the startDisplayLink and stopDisplayLink methods 
of the Objective-C class MTLLayer are invoked on multiple threads.

They are invoked on the AppKit main thread from screen sleep notifications and 
blitTexture.

They are invoked on the EDT from MTLLayer.validate.

They are invoked on the Queue Flusher thread from MTLRenderQueue.flushBuffer.

Perhaps someone familiar with this code could comment?


Reply via email to