Bug 1033

Summary: Guarantee atomicity of high-level GLAutoDrawable operations, avoiding race conditions.
Product: [JogAmp] Jogl Reporter: Sven Gothel <sgothel>
Component: coreAssignee: Sven Gothel <sgothel>
Status: RESOLVED FIXED    
Severity: major CC: askinner, sgothel
Priority: ---    
Version: 2   
Hardware: All   
OS: all   
Type: DEFECT SCM Refs:
c77b8f586cb2553582a42f5b90aeee5ef85f1efe
Workaround: ---

Description Sven Gothel 2014-07-15 04:09:14 CEST
Currently race-conditions are possible on the following 
high level utility method:

- GLDrawableUtil.swapGLContextAndAllGLEventListener(
                    GLAutoDrawable a, GLAutoDrawable b);

- GLEventListenerState.moveFrom(GLAutoDrawable src)
- GLEventListenerState.moveTo(GLAutoDrawable dest)

Their implementation lacks locking of
  [1] the GLAutoDrawable's NativeSurface, as well as of
  [2] the GLAutoDrawable's implementation own 'upstream' lock.

Locking of the NativeSurface is mandatory to hinder other threads
of acquiring the OpenGL context (lock).

Since GLAutoDrawable implementations also employ their own 
'high-level' lock, e.g. for modifying their surface/drawable,
it is important to acquire a lock on such beforehand.

Actual locking order of GLAutoDrawable is:
  1) GLAutoDrawable Lock
  2) NativeSurface Lock

(Note: GLContext.makeCurrent() acquires the NativeSurface Lock 1st.)

Allowing proper locking requires our API to expose 
the GLAutoDrawable 'upstream' lock!

Note: While holding the GLAutoDrawable locks, GLAutoDrawable.invoke(..) 
      cannot be issued, since it may be performed off-thread.
Comment 1 Sven Gothel 2014-07-27 23:26:06 CEST
c77b8f586cb2553582a42f5b90aeee5ef85f1efe

GLAutoDrawable (API CHANGE) allowing atomic operations:
    - Add class API-doc chapter about 'GLAutoDrawable Locking'

    - Add method invoke(..) API-doc description about 
      throwing IllegalStateException in case of a 
      detected deadlock situation ahead
      (Note: Implemented in GLDrawableHelper.invoke(..) for all implementations)

    - Add new methods for proper multithread handling:
    - public RecursiveLock getUpstreamLock();
    - public boolean isThreadGLCapable();

+++

GLEventListenerState/GLDrawableUtil:

    - Perform operation in a atomic fashion,
    i.e. lock GLAutoDrawable during whole operations:
        - GLDrawableUtil.swapGLContext(..)
        - GLDrawableUtil.swapGLContextAndAllGLEventListener(..)
        - GLEventListenerState.moveFrom(..)
        - GLEventListenerState.moveTo(..)

    - ReshapeGLEventListener:
    - Moved from 
        GLEventListenerState.ReshapeGLEventListener 
        ->  GLDrawableUtil.ReshapeGLEventListener
    - Takes 'displayAfterReshape' case into account.

+++

javax.media.opengl.Threading Clarifications:
    - Public 'enum Mode', i.e. Threading.Mode

    - Public getMode()

    - Clarified 'isOpenGLThread()':
    - Take 'singleThreaded' into account directly,
        i.e. always return 'true' if singleThreaded == false