Another OpenGL deadlock

Moving on to debugging on OS X, I'm having troubles with background OpenGL rendering and MessageManagerLocks again (http://www.juce.com/forum/topic/deadlock-due-lacking-documentation).

 

Deadlock occurs when running some UI code triggered by some event whilst rendering OpenGL using a OpenGLRenderer in which the renderOpenGL() method acquires a MessageManagerLock. 

I'm not 100% sure this is totally correct (as I can't debug the framework code and the Apple documentation is notoriously bad), although it's hard to see what else could be going on.

OS X window system on the main thread may try to query some information about the context at any point using the entry point CGLGetParameter. As OpenGL contexts are shared, they need to be protected by mutual exclusion. As we see on this image from the stacktrace that is deadlocked, the main thread acquires a lock (quite possibly the lock on the context): http://i.imgur.com/zbnc1eq.png

If this is the same lock as the Juce OpenGLRenderer thread acquires in OpenGLContext::CachedFrame::renderFrame in the NativeContext::Locker (which is a wrapper around the CGLLockContext/CGLUnlockContext), it appears to be unsafe to perform any form of synchronization, including MessageManagerLocks, between the main thread and the opengl thread. This does not seem to be documented anywhere (Apple included).

 

This only happens for OpenGLContexts, where setComponentPaintingEnabled(false) is set - otherwise, the context acquires a MessageManagerLock before locking the context, thus avoiding that the main thread tries to query the OpenGL context (as it will be locked before arriving to such a point). I'm not sure whether this can happen on Windows (or other platforms) as well.

 

Interested in hearing whether this sounds feasable and/or someone knows anything, or common workarounds for temporary synchronization - temporary being the point, if you synchronize the threads on OpenGL frame rendering, while you're maxing graphics out, you're stalling the main thread completely, for no reason.

e: this popped up: http://www.juce.com/forum/topic/opengl-deadlocks-mac - unfortunately, it was 'solved' by always syncing opengl and main thread (thus, turning multithreading into singlethreading) or never. I guess I'll go for the latter. Nevertheless, the documentation should indicate that syncing the main thread during onOpenGLRendering is unsafe.

I think the only solution is to really avoid using the MessageManagerLock inside the renderOpenGL callback. There are almost always other ways to do what you probably want to do without MessageManagerLock. For example, try to use FIFOs or copying data instead. Can you tell me exactly what you are trying to achieve and why you are trying to accquire the message lock?

I refactored it into using asynchronous messages. Use case was rather convoluted; I guess I was just frustrated that the JUCE documentation doesn't mention these corner cases.

I just ran into this as well. Please add some documentation to the juce::OpenGLRenderer that tells us not to use a MessageManagerLock in the rendering functions!!

1 Like

I just ran into this exact problem again. Please, for the love of god, add a line to the documentation telling people not to acquire a MessageManagerLock in the OpenGL rendering functions!

1 Like