diff options
Diffstat (limited to 'src/nativewindow/classes/com/jogamp')
4 files changed, 161 insertions, 142 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/LockingNativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/LockingNativeWindowFactory.java index fd2478ab2..203ae3d12 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/LockingNativeWindowFactory.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/LockingNativeWindowFactory.java @@ -35,39 +35,7 @@ package com.jogamp.nativewindow.impl; import javax.media.nativewindow.*; public class LockingNativeWindowFactory extends NativeWindowFactoryImpl { - // Provides a generic basic and recursive locking mechanism for your discretion. - private ToolkitLock toolkitLock = new ToolkitLock() { - private Thread owner; - private int recursionCount; - - public synchronized void lock() { - Thread cur = Thread.currentThread(); - if (owner == cur) { - ++recursionCount; - return; - } - while (owner != null) { - try { - wait(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - owner = cur; - } - - public synchronized void unlock() { - if (owner != Thread.currentThread()) { - throw new RuntimeException("Not owner"); - } - if (recursionCount > 0) { - --recursionCount; - return; - } - owner = null; - notifyAll(); - } - }; + private ToolkitLock toolkitLock = new RecursiveToolkitLock(); public ToolkitLock getToolkitLock() { return toolkitLock; diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java new file mode 100644 index 000000000..06ce54368 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java @@ -0,0 +1,83 @@ +package com.jogamp.nativewindow.impl; + +import javax.media.nativewindow.*; + +// +// Reentrance locking toolkit +// +public class RecursiveToolkitLock implements ToolkitLock { + private Thread owner; + private int recursionCount; + private Exception lockedStack = null; + private static final long timeout = 3000; // maximum wait 3s + + public Exception getLockedStack() { + return lockedStack; + } + + public Thread getOwner() { + return owner; + } + + public boolean isOwner() { + return isOwner(Thread.currentThread()); + } + + public synchronized boolean isOwner(Thread thread) { + return owner == thread ; + } + + public synchronized boolean isLocked() { + return null != owner; + } + + /** Recursive and blocking lockSurface() implementation */ + public synchronized void lock() { + Thread cur = Thread.currentThread(); + if (owner == cur) { + ++recursionCount; + return; + } + + long ts = System.currentTimeMillis(); + while (owner != null && (System.currentTimeMillis()-ts) < timeout) { + try { + wait(timeout); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + if(owner != null) { + lockedStack.printStackTrace(); + throw new RuntimeException("Waited "+timeout+"ms for: "+owner+" - "+cur); + } + owner = cur; + lockedStack = new Exception("Previously locked by "+owner); + } + + + /** Recursive and unblocking unlockSurface() implementation */ + public synchronized void unlock() { + unlock(null); + } + + /** Recursive and unblocking unlockSurface() implementation */ + public synchronized void unlock(Runnable releaseAfterUnlockBeforeNotify) { + Thread cur = Thread.currentThread(); + if (owner != cur) { + lockedStack.printStackTrace(); + throw new RuntimeException(cur+": Not owner, owner is "+owner); + } + if (recursionCount > 0) { + --recursionCount; + return; + } + owner = null; + lockedStack = null; + if(null!=releaseAfterUnlockBeforeNotify) { + releaseAfterUnlockBeforeNotify.run(); + } + notifyAll(); + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java index a6f52f3c0..0cd02558a 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java @@ -58,7 +58,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor int num[] = { -1 }; long display = screen.getDevice().getHandle(); - X11Lib.XLockDisplay(display); + X11Util.XLockDisplay(display); try { XVisualInfo[] xvis = X11Lib.XGetVisualInfoCopied(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); @@ -68,7 +68,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor return XVisualInfo.create(xvis[0]); } finally { - X11Lib.XUnlockDisplay(display); + X11Util.XUnlockDisplay(display); } } @@ -90,7 +90,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor vinfo_template.setC_class(c_class); long display = screen.getDevice().getHandle(); - X11Lib.XLockDisplay(display); + X11Util.XLockDisplay(display); try { XVisualInfo[] vinfos = X11Lib.XGetVisualInfoCopied(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); XVisualInfo best=null; @@ -111,7 +111,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor return ret; } finally { - X11Lib.XUnlockDisplay(display); + X11Util.XUnlockDisplay(display); } } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java index 5f5c10885..d93302e57 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; +import com.jogamp.common.util.LongObjectHashMap; import javax.media.nativewindow.*; @@ -51,25 +52,29 @@ import com.jogamp.nativewindow.impl.*; */ public class X11Util { private static final boolean DEBUG = Debug.debug("X11Util"); + private static final boolean DEBUG_XDISPLAY_LOCK = false; static { NWJNILibLoader.loadNativeWindow("x11"); - installIOErrorHandler(); + initialize(); } - private X11Util() {} + public static void initSingleton() { + // just exist to ensure static init has been run + } - private static ThreadLocal currentDisplayMap = new ThreadLocal(); + private X11Util() {} // not exactly thread safe, but good enough for our purpose, // which is to tag a NamedDisplay uncloseable after creation. private static Object globalLock = new Object(); - private static Collection globalNamedDisplayActive = new ArrayList(); - private static Collection globalNamedDisplayPassive = new ArrayList(); + private static LongObjectHashMap globalNamedDisplayMap = new LongObjectHashMap(); + + private static ThreadLocal currentDisplayMap = new ThreadLocal(); public static final String nullDeviceName = "nil" ; - public static class NamedDisplay implements Cloneable { + public static class NamedDisplay extends RecursiveToolkitLock implements Cloneable { String name; long handle; int refCount; @@ -102,10 +107,9 @@ public class X11Util { */ public static int shutdown(boolean realXClosePendingDisplays, boolean verbose) { int num=0; - String msg; + String msg = null; if(DEBUG||verbose) { - msg = "X11Util.Display: Shutdown (active: "+globalNamedDisplayActive.size()+ - ", passive: "+globalNamedDisplayPassive.size() + ")"; + msg = "X11Util.Display: Shutdown (global: "+globalNamedDisplayMap.size()+ ")" ; if(DEBUG) { Exception e = new Exception(msg); e.printStackTrace(); @@ -114,36 +118,8 @@ public class X11Util { } } - msg = realXClosePendingDisplays ? "Close" : "Keep" ; - synchronized(globalLock) { - // for all passive displays .. - Collection namedDisplays = globalNamedDisplayPassive; - globalNamedDisplayPassive = new ArrayList(); - for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) { - NamedDisplay ndpy = (NamedDisplay)iter.next(); - if(DEBUG||verbose) { - System.err.println(msg+" passive: "+ndpy); - } - if(realXClosePendingDisplays) { - X11Lib.XCloseDisplay(ndpy.getHandle()); - } - num++; - } - - // for all active displays .. - namedDisplays = globalNamedDisplayActive; - globalNamedDisplayActive = new ArrayList(); - for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) { - NamedDisplay ndpy = (NamedDisplay)iter.next(); - if(DEBUG||verbose) { - System.err.println(msg+" active: "+ndpy); - } - if(realXClosePendingDisplays) { - X11Lib.XCloseDisplay(ndpy.getHandle()); - } - num++; - } + globalNamedDisplayMap.clear(); } return num; } @@ -162,24 +138,14 @@ public class X11Util { public static long createThreadLocalDisplay(String name) { NamedDisplay namedDpy = getCurrentDisplay(name); if(null==namedDpy) { - synchronized(globalLock) { - namedDpy = getNamedDisplay(globalNamedDisplayPassive, name); - if(null != namedDpy) { - if(!globalNamedDisplayPassive.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } - globalNamedDisplayActive.add(namedDpy); - addCurrentDisplay( namedDpy ); - } - } - } - if(null==namedDpy) { long dpy = X11Lib.XOpenDisplay(name); if(0==dpy) { throw new NativeWindowException("X11Util.Display: Unable to create a display("+name+") connection in Thread "+Thread.currentThread().getName()); } namedDpy = new NamedDisplay(name, dpy); + addCurrentDisplay( namedDpy ); synchronized(globalLock) { - globalNamedDisplayActive.add(namedDpy); - addCurrentDisplay( namedDpy ); + globalNamedDisplayMap.put(dpy, namedDpy); } if(DEBUG) { Exception e = new Exception("X11Util.Display: Created new TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); @@ -203,7 +169,7 @@ public class X11Util { public static long closeThreadLocalDisplay(String name) { NamedDisplay namedDpy = getCurrentDisplay(name); if(null==namedDpy) { - throw new RuntimeException("X11Util.Display: Display("+name+") with given handle is not mapped to TLS in thread "+Thread.currentThread().getName()); + throw new RuntimeException("X11Util.Display: Display("+name+") with given name is not mapped to TLS in thread "+Thread.currentThread().getName()); } if(0==namedDpy.refCount) { throw new RuntimeException("X11Util.Display: "+namedDpy+" has refCount already 0 in thread "+Thread.currentThread().getName()); @@ -211,20 +177,18 @@ public class X11Util { long dpy = namedDpy.getHandle(); namedDpy.refCount--; if(0==namedDpy.refCount) { - synchronized(globalLock) { - if(!globalNamedDisplayActive.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } - if(namedDpy.isUncloseable()) { - globalNamedDisplayPassive.add(namedDpy); - } else { - X11Lib.XCloseDisplay(dpy); - } - removeCurrentDisplay(namedDpy); - } if(DEBUG) { String type = namedDpy.isUncloseable() ? "passive" : "real" ; Exception e = new Exception("X11Util.Display: Closing ( "+type+" ) TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); e.printStackTrace(); } + removeCurrentDisplay(namedDpy); + synchronized(globalLock) { + if(null==globalNamedDisplayMap.remove(dpy)) { throw new RuntimeException("Internal: "+namedDpy); } + } + if(!namedDpy.isUncloseable()) { + X11Lib.XCloseDisplay(dpy); + } } else if(DEBUG) { Exception e = new Exception("X11Util.Display: Keep TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); e.printStackTrace(); @@ -232,39 +196,64 @@ public class X11Util { return dpy; } - public static String getThreadLocalDisplayName(long handle) { - NamedDisplay ndpy = getNamedDisplay(getCurrentDisplayMapImpl().values(), handle); - return null != ndpy ? ndpy.getName() : null; + public static long closeThreadLocalDisplay(long handle) { + NamedDisplay ndpy; + synchronized(globalLock) { + ndpy = (NamedDisplay) globalNamedDisplayMap.get(handle); + } + if(null==ndpy) { + throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped, in thread "+Thread.currentThread().getName()); + } + return closeThreadLocalDisplay(ndpy.getName()); } - public static boolean markThreadLocalDisplayUndeletable(long handle) { - NamedDisplay ndpy = getNamedDisplay(getCurrentDisplayMapImpl().values(), handle); - if( null != ndpy ) { - ndpy.unCloseable=true; - return true; + public static void XLockDisplay(long handle) { + if(DEBUG_XDISPLAY_LOCK) { + NamedDisplay ndpy; + synchronized(globalLock) { + ndpy = (NamedDisplay) globalNamedDisplayMap.get(handle); + } + if(null==ndpy) { + throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped, thread "+Thread.currentThread().getName()); + } + ndpy.lock(); + try { + X11Lib.XLockDisplay(handle); + } catch (Throwable t) { + ndpy.unlock(); + throw new RuntimeException(t); + } + } else { + X11Lib.XLockDisplay(handle); } - return false; } - public static String getGlobalDisplayName(long handle, boolean active) { - String name; - synchronized(globalLock) { - NamedDisplay ndpy = getNamedDisplay(active ? globalNamedDisplayActive : globalNamedDisplayPassive, handle); - name = null != ndpy ? ndpy.getName() : null; + public static void XUnlockDisplay(long handle) { + if(DEBUG_XDISPLAY_LOCK) { + NamedDisplay ndpy; + synchronized(globalLock) { + ndpy = (NamedDisplay) globalNamedDisplayMap.get(handle); + } + if(null==ndpy) { + throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped, thread "+Thread.currentThread().getName()); + } + X11Lib.XUnlockDisplay(handle); + ndpy.unlock(); + } else { + X11Lib.XUnlockDisplay(handle); } - return name; } - public static boolean markGlobalDisplayUndeletable(long handle) { - boolean r=false; + public static boolean markThreadLocalDisplayUncloseable(long handle) { + NamedDisplay ndpy; synchronized(globalLock) { - NamedDisplay ndpy = getNamedDisplay(globalNamedDisplayActive, handle); - if( null != ndpy ) { - ndpy.unCloseable=true; - r=true; - } + ndpy = (NamedDisplay) globalNamedDisplayMap.get(handle); + } + if( null != ndpy ) { + ndpy.unCloseable=true; + return true; } - return r; + return false; } private static Map getCurrentDisplayMapImpl() { @@ -309,26 +298,5 @@ public class X11Util { return (NamedDisplay) displayMap.get(name); } - private static NamedDisplay getNamedDisplay(Collection namedDisplays, String name) { - if(null==name) name=nullDeviceName; - for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) { - NamedDisplay ndpy = (NamedDisplay)iter.next(); - if (ndpy.getNameSafe().equals(name)) { - return ndpy; - } - } - return null; - } - - private static NamedDisplay getNamedDisplay(Collection namedDisplays, long handle) { - for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) { - NamedDisplay ndpy = (NamedDisplay)iter.next(); - if (ndpy.getHandle()==handle) { - return ndpy; - } - } - return null; - } - - private static native void installIOErrorHandler(); + private static native void initialize(); } |