From 92398025abdabb2fdef0d78edd41e730991a6f94 Mon Sep 17 00:00:00 2001
From: Sven Gothel
diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
index b16b0c75c..9288652d9 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
@@ -60,7 +60,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
/**
* Create an instance with the system default {@link ToolkitLock}.
- * gathered via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}.
+ * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}.
* @param type
* @param handle
*/
@@ -70,7 +70,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
this.unitID = unitID;
this.uniqueID = getUniqueID(type, connection, unitID);
this.handle = handle;
- this.toolkitLock = NativeWindowFactory.createDefaultToolkitLock(type, handle);
+ this.toolkitLock = NativeWindowFactory.getDefaultToolkitLock(type, handle);
}
/**
@@ -123,8 +123,10 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
}
/**
- * No lock is performed on the graphics device per default,
- * instead the aggregated recursive {@link ToolkitLock#lock()} is invoked.
+ * {@inheritDoc}
+ *
+ * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}.
+ *
+ * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}.
+ *
+ * The JAWT based {@link ToolkitLock} also locks the global lock,
+ * which matters if the latter is required.
+ * null
.
*
+ * Provides the system default {@link ToolkitLock} for the default system windowing type.
+ * @see #getNativeWindowType(boolean)
* @see #getDefaultToolkitLock(java.lang.String)
*/
public static ToolkitLock getDefaultToolkitLock() {
@@ -341,57 +377,44 @@ public abstract class NativeWindowFactory {
}
/**
- * Provides the default {@link ToolkitLock} for type
, a singleton instance.
+ * Provides the default {@link ToolkitLock} for type
.
*
- *
*/
public static ToolkitLock getDefaultToolkitLock(String type) {
- if( requiresToolkitLock() ) {
- if( TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) && isAWTAvailable() ) {
+ if( requiresToolkitLock ) {
+ if( TYPE_AWT == type && isAWTAvailable() ) {
return getAWTToolkitLock();
}
- }
- return NativeWindowFactoryImpl.getNullToolkitLock();
- }
-
- /** Returns the AWT Toolkit (JAWT based) if {@link #isAWTAvailable}, otherwise null. */
- public static ToolkitLock getAWTToolkitLock() {
- return jawtUtilJAWTToolkitLock;
- }
-
- public static ToolkitLock getNullToolkitLock() {
- return NativeWindowFactoryImpl.getNullToolkitLock();
- }
-
- /**
- * Creates the default {@link ToolkitLock} for type
is of {@link #TYPE_AWT} and AWT available,type
and deviceHandle
.
- *
- *
- */
- public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) {
- if( requiresToolkitLock() ) {
+ if( requiresGlobalToolkitLock ) {
+ return NativeWindowFactoryImpl.getGlobalToolkitLock();
+ }
return ResourceToolkitLock.create();
}
return NativeWindowFactoryImpl.getNullToolkitLock();
}
-
+
/**
- * Creates the default {@link ToolkitLock} for type
and deviceHandle
.
+ * Provides the default {@link ToolkitLock} for type
and deviceHandle
.
*
- *
*/
- public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) {
- if( requiresToolkitLock() ) {
- if( TYPE_AWT == sharedType && isAWTAvailable() ) {
+ public static ToolkitLock getDefaultToolkitLock(String type, long deviceHandle) {
+ if( requiresToolkitLock ) {
+ if( TYPE_AWT == type && isAWTAvailable() ) {
return getAWTToolkitLock();
}
+ if( requiresGlobalToolkitLock ) {
+ return NativeWindowFactoryImpl.getGlobalToolkitLock();
+ }
return ResourceToolkitLock.create();
}
return NativeWindowFactoryImpl.getNullToolkitLock();
diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java
index 18b7cf5d9..eccfcfa4f 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java
@@ -37,15 +37,35 @@ import jogamp.nativewindow.Debug;
* Toolkit locks are created solely via {@link NativeWindowFactory}.
* type
is of {@link #TYPE_AWT} and AWT available,
- * One use case is the AWT locking on X11, see {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * One use case is the AWT locking on X11, see {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. *
*/ public interface ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true); + /** + * Blocking until the lock is acquired by this Thread or a timeout is reached. + *+ * Timeout is implementation specific, if used at all. + *
+ * + * @throws RuntimeException in case of a timeout + */ public void lock(); + + /** + * Release the lock. + * + * @throws RuntimeException in case the lock is not acquired by this thread. + */ public void unlock(); + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + /** * Dispose this instance. *diff --git a/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java new file mode 100644 index 000000000..0c2a1e43f --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java @@ -0,0 +1,75 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.nativewindow; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a global recursive {@link javax.media.nativewindow.ToolkitLock}. + *
+ * This is the last resort for unstable driver, e.g. proprietary ATI/X11 12.8 and 12.9, + * where multiple X11 display connections to the same connection name are not treated + * thread safe within the GL/X11 driver. + *
+ */ +public class GlobalToolkitLock implements ToolkitLock { + private static final RecursiveLock globalLock = LockFactory.createRecursiveLock(); + + /** Singleton via {@link NativeWindowFactoryImpl#getGlobalToolkitLock()} */ + protected GlobalToolkitLock() { } + + @Override + public final void lock() { + globalLock.lock(); + if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.lock()"); } + } + + @Override + public final void unlock() { + if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.unlock()"); } + globalLock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + globalLock.validateLocked(); + } + + @Override + public final void dispose() { + // nop + } + + public String toString() { + return "GlobalToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+globalLock.isOwner(Thread.currentThread())+", "+globalLock.toString()+"]"; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index 29564da3b..c35cede77 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -44,9 +44,14 @@ import com.jogamp.common.util.ReflectionUtil.AWTNames; public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); + private static final ToolkitLock globalToolkitLock = new GlobalToolkitLock(); public static ToolkitLock getNullToolkitLock() { - return nullToolkitLock; + return nullToolkitLock; + } + + public static ToolkitLock getGlobalToolkitLock() { + return globalToolkitLock; } // This subclass of NativeWindowFactory handles the case of diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java index e59910138..211e15955 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java @@ -31,15 +31,16 @@ package jogamp.nativewindow; import javax.media.nativewindow.ToolkitLock; /** - * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock} - * without any locking. Since there is no locking it all, - * it is intrinsically recursive. + * Implementing a singleton global NOP {@link javax.media.nativewindow.ToolkitLock} + * without any locking. Since there is no locking it all, it is intrinsically recursive. */ public class NullToolkitLock implements ToolkitLock { - + public static final boolean INVALID_LOCKED = Debug.isPropertyDefined("nativewindow.debug.NullToolkitLock.InvalidLocked", true); + /** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */ protected NullToolkitLock() { } + @Override public final void lock() { if(TRACE_LOCK) { System.err.println("NullToolkitLock.lock()"); @@ -47,10 +48,20 @@ public class NullToolkitLock implements ToolkitLock { } } + @Override public final void unlock() { if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } } + @Override + public final void validateLocked() throws RuntimeException { + /* nop */ + if(INVALID_LOCKED) { + throw new RuntimeException("NullToolkitLock does not lock"); + } + } + + @Override public final void dispose() { // nop } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java index a3b0804fa..5b79de0b8 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java @@ -41,8 +41,6 @@ import com.jogamp.common.util.locks.RecursiveLock; * */ public class ResourceToolkitLock implements ToolkitLock { - public static final boolean DEBUG = Debug.debug("ToolkitLock"); - public static final ResourceToolkitLock create() { return new ResourceToolkitLock(); } @@ -53,17 +51,24 @@ public class ResourceToolkitLock implements ToolkitLock { this.lock = LockFactory.createRecursiveLock(); } - + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); } lock.lock(); + if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); } } + @Override public final void unlock() { if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.unlock()"); } - lock.unlock(); + lock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); } + @Override public final void dispose() { // nop } diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java index 5d7ae8abb..94d12e6fc 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -49,7 +49,6 @@ import com.jogamp.common.util.locks.RecursiveLock; * */ public class SharedResourceToolkitLock implements ToolkitLock { - public static final boolean DEBUG = Debug.debug("ToolkitLock"); private static final LongObjectHashMap handle2Lock; static { handle2Lock = new LongObjectHashMap(); @@ -109,16 +108,24 @@ public class SharedResourceToolkitLock implements ToolkitLock { } + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); } lock.lock(); + if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); } } + @Override public final void unlock() { if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.unlock()"); } lock.unlock(); } + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); + } + + @Override public final void dispose() { if(0 < refCount) { // volatile OK synchronized(handle2Lock) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java new file mode 100644 index 000000000..2062d1f58 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java @@ -0,0 +1,51 @@ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; + +/** + * Marker interface. + *+ * Implementation requires to provide static methods: + *
+ public static void initSingleton() {} + + public static void shutdown() {} + + public static boolean requiresToolkitLock() {} + + public static boolean requiresGlobalToolkitLock() {} + *+ * Above static methods are invoked by {@link NativeWindowFactory#initSingleton()}, + * or {@link NativeWindowFactory#shutdown()} via reflection. + * + *
+ * If requiresGlobalToolkitLock() == true
, then
+ * requiresToolkitLock() == true
shall be valid as well.
+ *
+ * Called by {@link NativeWindowFactory#shutdown()} + *
+ */ + // void shutdown(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean requiresToolkitLock(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean requiresGlobalToolkitLock(); + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index 7c934b154..2dadfb16b 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -79,6 +79,8 @@ public class JAWTUtil { private static final Method sunToolkitAWTLockMethod; private static final Method sunToolkitAWTUnlockMethod; private static final boolean hasSunToolkitAWTLock; + + private static volatile Thread exclusiveOwnerThread; private static final ToolkitLock jawtToolkitLock; @@ -229,13 +231,23 @@ public class JAWTUtil { } hasSunToolkitAWTLock = _hasSunToolkitAWTLock; // hasSunToolkitAWTLock = false; + exclusiveOwnerThread = null; jawtToolkitLock = new ToolkitLock() { public final void lock() { + NativeWindowFactory.getGlobalToolkitLock().lock(); JAWTUtil.lockToolkit(); + if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.lock()"); } } public final void unlock() { + if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.unlock()"); } JAWTUtil.unlockToolkit(); + NativeWindowFactory.getGlobalToolkitLock().unlock(); + } + @Override + public final void validateLocked() throws RuntimeException { + NativeWindowFactory.getGlobalToolkitLock().validateLocked(); + JAWTUtil.validateLocked(); } public final void dispose() { // nop @@ -312,7 +324,7 @@ public class JAWTUtil { * JAWT's native Lock() function calls SunToolkit.awtLock(), * which just uses AWT's global ReentrantLock.@@ -88,11 +90,15 @@ public class X11Util { private static String nullDisplayName = null; private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues + private static boolean requiresGlobalToolkitLock = false; // ATI/AMD X11 driver issues private static Object setX11ErrorHandlerLock = new Object(); + private static final String X11_EXTENSION_ATIFGLRXDRI = "ATIFGLRXDRI"; + private static final String X11_EXTENSION_ATIFGLEXTENSION = "ATIFGLEXTENSION"; /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static void initSingleton() { if(!isInit) { @@ -100,7 +106,7 @@ public class X11Util { if(!isInit) { isInit = true; if(DEBUG) { - System.out.println("X11UtilUtil.initSingleton()"); + System.out.println("X11Util.initSingleton()"); } if(!NWJNILibLoader.loadNativeWindow("x11")) { throw new NativeWindowException("NativeWindow X11 native library load error."); @@ -108,6 +114,7 @@ public class X11Util { final boolean isInitOK = initialize0( XERROR_STACKDUMP ); + final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION; final long dpy = X11Lib.XOpenDisplay(null); if(0 != dpy) { if(XSYNC_ENABLED) { @@ -115,17 +122,29 @@ public class X11Util { } try { nullDisplayName = X11Lib.XDisplayString(dpy); + hasX11_EXTENSION_ATIFGLRXDRI = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLRXDRI); + hasX11_EXTENSION_ATIFGLEXTENSION = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLEXTENSION); } finally { X11Lib.XCloseDisplay(dpy); } } else { nullDisplayName = "nil"; + hasX11_EXTENSION_ATIFGLRXDRI = false; + hasX11_EXTENSION_ATIFGLEXTENSION = false; } + requiresGlobalToolkitLock = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION; + markAllDisplaysUnclosable = ATI_HAS_XCLOSEDISPLAY_BUG && ( hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION ); if(DEBUG) { - System.err.println("X11Util init OK "+isInitOK+"]"+ - ", X11 Display(NULL) <"+nullDisplayName+">"+ - ", XSynchronize Enabled: "+XSYNC_ENABLED); + System.err.println("X11Util.initSingleton(): OK "+isInitOK+"]"+ + ",\n\t X11 Display(NULL) <"+nullDisplayName+">"+ + ",\n\t XSynchronize Enabled: " + XSYNC_ENABLED+ + ",\n\t X11_EXTENSION_ATIFGLRXDRI " + hasX11_EXTENSION_ATIFGLRXDRI+ + ",\n\t X11_EXTENSION_ATIFGLEXTENSION " + hasX11_EXTENSION_ATIFGLEXTENSION+ + ",\n\t requiresToolkitLock "+requiresToolkitLock()+ + ",\n\t requiresGlobalToolkitLock "+requiresGlobalToolkitLock()+ + ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable() + ); // Thread.dumpStack(); } } @@ -147,6 +166,7 @@ public class X11Util { *
* Called by {@link NativeWindowFactory#shutdown()} *
+ * @see ToolkitProperties */ public static void shutdown() { if(isInit) { @@ -189,8 +209,20 @@ public class X11Util { } } - public static boolean requiresToolkitLock() { - return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock. + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean requiresToolkitLock() { + return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock per display connection. + } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean requiresGlobalToolkitLock() { + return requiresGlobalToolkitLock; // JAWT locking: yes, instead of native X11 locking w use a global lock. } public static void setX11ErrorHandler(boolean onoff, boolean quiet) { @@ -206,9 +238,6 @@ public class X11Util { public static boolean getMarkAllDisplaysUnclosable() { return markAllDisplaysUnclosable; } - public static void setMarkAllDisplaysUnclosable(boolean v) { - markAllDisplaysUnclosable = v; - } private X11Util() {} @@ -373,7 +402,7 @@ public class X11Util { name = validateDisplayName(name); boolean reused = false; - synchronized(globalLock) { + synchronized(globalLock) { for(int i=0; i