From 453ccee8e3ce90956756d1582852b13f45cd2f38 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 9 Jul 2013 15:04:50 +0200 Subject: NEWT EDTUtil: Exposed weakness of EDTUtil usage due to usage of WeakReference, i.e. higher retention of Display instances. - WeakReference Change 99479bf3197cde8e89c5b499d135417863d521c7 - Refines commits: feb352145af1643a57eaae99c0342e6f5e0f2a2e dec4b02fe4b93028c85de6a56b6af79601042d6e 433e3914324b90c910b018bb7d9d80e814c67123 Reviews EDTUtil API and usage: - less confusing / more determined EDTUtil API - EDTUtil's thread shall only be reset and started when required (-> lazy) - EDTUtil's instance in Display shall be handled thread safe w/o extra blocking - EDTUtil's implementations (Default, SWT and AWT) shall be aligned / similar as much as possible Further note: SWT's EDTUtil (NewtCanvasSWT) shall not use a reused Display instance due to it's custom SWTEDTUtil. We may need to disable the ref. cache if custom EDTUtil (setEDTUtil) is intended (used). --- src/newt/classes/jogamp/newt/DefaultEDTUtil.java | 115 ++++++++------- src/newt/classes/jogamp/newt/DisplayImpl.java | 137 +++++++++++------- .../jogamp/newt/driver/android/DisplayDriver.java | 2 +- .../classes/jogamp/newt/driver/awt/AWTEDTUtil.java | 130 ++++++++++------- .../jogamp/newt/driver/awt/DisplayDriver.java | 4 +- .../jogamp/newt/driver/bcm/egl/DisplayDriver.java | 2 +- .../newt/driver/bcm/vc/iv/DisplayDriver.java | 2 +- .../newt/driver/intel/gdl/DisplayDriver.java | 2 +- .../jogamp/newt/driver/kd/DisplayDriver.java | 2 +- .../jogamp/newt/driver/macosx/DisplayDriver.java | 2 +- .../jogamp/newt/driver/windows/DisplayDriver.java | 2 +- .../jogamp/newt/driver/x11/DisplayDriver.java | 4 +- src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java | 161 +++++++++++++-------- 13 files changed, 332 insertions(+), 233 deletions(-) (limited to 'src/newt/classes/jogamp') diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java index ecd94c278..a229a0512 100644 --- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java +++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java @@ -53,7 +53,7 @@ public class DefaultEDTUtil implements EDTUtil { private final ThreadGroup threadGroup; private final String name; private final Runnable dispatchMessages; - private EventDispatchThread edt = null; + private NEDT edt = null; private int start_iter=0; private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; @@ -61,7 +61,7 @@ public class DefaultEDTUtil implements EDTUtil { this.threadGroup = tg; this.name=Thread.currentThread().getName()+"-"+name+"-EDT-"; this.dispatchMessages=dispatchMessages; - this.edt = new EventDispatchThread(threadGroup, name); + this.edt = new NEDT(threadGroup, name); this.edt.setDaemon(true); // don't stop JVM from shutdown .. } @@ -76,36 +76,34 @@ public class DefaultEDTUtil implements EDTUtil { } @Override - public final void reset() throws IllegalStateException { + public final boolean restart() throws IllegalStateException { synchronized(edtLock) { - if( isRunning() ) { - if( !edt.shouldStop ) { - throw new IllegalStateException("EDT stop not issued."); - } - throw new IllegalStateException("EDT still running"); + if( edt.isRunning() ) { + throw new IllegalStateException("EDT still running and not subject to stop. Curr "+Thread.currentThread().getName()+", EDT "+edt.getName()+", isRunning "+edt.isRunning+", shouldStop "+edt.shouldStop); } if(DEBUG) { if(edt.tasks.size()>0) { System.err.println(Thread.currentThread()+": Default-EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt); - // Thread.dumpStack(); } System.err.println(Thread.currentThread()+": Default-EDT reset - edt: "+edt); } - this.edt = new EventDispatchThread(threadGroup, name); - this.edt.setDaemon(true); // don't stop JVM from shutdown .. + if( edt.getState() != Thread.State.NEW ) { + edt = new NEDT(threadGroup, name); + edt.setDaemon(true); // don't stop JVM from shutdown .. + } + startImpl(); } + return invoke(true, nullTask); } private final void startImpl() { if(edt.isAlive()) { - throw new RuntimeException("Default-EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size()); + throw new RuntimeException("Default-EDT Thread.isAlive(): true, isRunning: "+edt.isRunning+", shouldStop "+edt.shouldStop+", edt: "+edt+", tasks: "+edt.tasks.size()); } start_iter++; edt.setName(name+start_iter); - edt.shouldStop = false; if(DEBUG) { System.err.println(Thread.currentThread()+": Default-EDT START - edt: "+edt); - // Thread.dumpStack(); } edt.start(); } @@ -131,13 +129,13 @@ public class DefaultEDTUtil implements EDTUtil { } @Override - public final void invokeStop(boolean wait, Runnable task) { - invokeImpl(wait, task, true); + public final boolean invokeStop(boolean wait, Runnable task) { + return invokeImpl(wait, task, true); } @Override - public final void invoke(boolean wait, Runnable task) { - invokeImpl(wait, task, false); + public final boolean invoke(boolean wait, Runnable task) { + return invokeImpl(wait, task, false); } private static Runnable nullTask = new Runnable() { @@ -145,28 +143,26 @@ public class DefaultEDTUtil implements EDTUtil { public void run() { } }; - private void invokeImpl(boolean wait, Runnable task, boolean stop) { + private final boolean invokeImpl(boolean wait, Runnable task, boolean stop) { Throwable throwable = null; RunnableTask rTask = null; - Object rTaskLock = new Object(); + final Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution synchronized(edtLock) { // lock the EDT status if( edt.shouldStop ) { // drop task .. + System.err.println(Thread.currentThread()+": Warning: Default-EDT about (1) to stop, won't enqueue new task: "+edt); if(DEBUG) { - System.err.println(Thread.currentThread()+": Warning: Default-EDT about (1) to stop, won't enqueue new task: "+edt); Thread.dumpStack(); } - return; + return false; } - // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); - // Thread.dumpStack(); if( isCurrentThreadEDT() ) { if(null != task) { task.run(); } wait = false; // running in same thread (EDT) -> no wait - if(stop) { + if( stop ) { edt.shouldStop = true; if( edt.tasks.size()>0 ) { System.err.println(Thread.currentThread()+": Warning: Default-EDT about (2) to stop, task executed. Remaining tasks: "+edt.tasks.size()+" - "+edt); @@ -176,21 +172,19 @@ public class DefaultEDTUtil implements EDTUtil { } } } else { - if( !edt.isRunning() ) { - if( !stop ) { - startImpl(); - if( wait && null == task ) { - task = nullTask; // ensures wait until started + if( !edt.isRunning ) { + if( null != task ) { + if( stop ) { + System.err.println(Thread.currentThread()+": Warning: Default-EDT is about (3) to stop and stopped already, dropping task. Remaining tasks: "+edt.tasks.size()+" - "+edt); + } else { + System.err.println(Thread.currentThread()+": Warning: Default-EDT is not running, dropping task. NEDT "+edt); } - } else { - // drop task and don't wait - task = null; - System.err.println(Thread.currentThread()+": Warning: Default-EDT is about (3) to stop and stopped already, dropping task. Remaining tasks: "+edt.tasks.size()+" - "+edt); if(DEBUG) { Thread.dumpStack(); } } - } else if(stop && null == task) { + return false; + } else if( stop && null == task ) { task = nullTask; // ensures execution triggering stop } @@ -228,23 +222,26 @@ public class DefaultEDTUtil implements EDTUtil { throw new RuntimeException(throwable); } } - } - if(DEBUG && stop) { - System.err.println(Thread.currentThread()+": Default-EDT signal STOP X edt: "+edt); + if(DEBUG) { + if( stop) { + System.err.println(Thread.currentThread()+": Default-EDT signal STOP X edt: "+edt); + } + } + return true; } } @Override - final public void waitUntilIdle() { - final EventDispatchThread _edt; + final public boolean waitUntilIdle() { + final NEDT _edt; synchronized(edtLock) { _edt = edt; } - if(!_edt.isRunning() || _edt == Thread.currentThread()) { - return; + if(!_edt.isRunning || _edt == Thread.currentThread()) { + return false; } synchronized(_edt.tasks) { - while(_edt.isRunning() && _edt.tasks.size()>0) { + while(_edt.isRunning && _edt.tasks.size()>0) { try { _edt.tasks.notifyAll(); _edt.tasks.wait(); @@ -252,35 +249,39 @@ public class DefaultEDTUtil implements EDTUtil { e.printStackTrace(); } } + return true; } } @Override - final public void waitUntilStopped() { + final public boolean waitUntilStopped() { synchronized(edtLock) { - if(edt.isRunning() && edt != Thread.currentThread() ) { - while(edt.isRunning()) { + if(edt.isRunning && edt != Thread.currentThread() ) { + while( edt.isRunning ) { try { edtLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } + return true; + } else { + return false; } } } - class EventDispatchThread extends Thread { + class NEDT extends Thread { volatile boolean shouldStop = false; volatile boolean isRunning = false; ArrayList tasks = new ArrayList(); // one shot tasks - public EventDispatchThread(ThreadGroup tg, String name) { + public NEDT(ThreadGroup tg, String name) { super(tg, name); } final public boolean isRunning() { - return isRunning; + return isRunning && !shouldStop; } @Override @@ -290,11 +291,9 @@ public class DefaultEDTUtil implements EDTUtil { } private final void validateNoRecursiveLocksHold() { - if(Lock.DEBUG) { - if(LockDebugUtil.getRecursiveLockTrace().size()>0) { - LockDebugUtil.dumpRecursiveLockTrace(System.err); - throw new InternalError("XXX"); - } + if(LockDebugUtil.getRecursiveLockTrace().size()>0) { + LockDebugUtil.dumpRecursiveLockTrace(System.err); + throw new InternalError("XXX"); } } @@ -307,7 +306,9 @@ public class DefaultEDTUtil implements EDTUtil { if(DEBUG) { System.err.println(getName()+": Default-EDT run() START "+ getName()); } - validateNoRecursiveLocksHold(); + if(Lock.DEBUG) { + validateNoRecursiveLocksHold(); + } RuntimeException error = null; try { do { @@ -337,7 +338,9 @@ public class DefaultEDTUtil implements EDTUtil { } if(null!=task) { task.run(); - validateNoRecursiveLocksHold(); + if(Lock.DEBUG) { + validateNoRecursiveLocksHold(); + } if(!task.hasWaiter() && null != task.getThrowable()) { // at least dump stack-trace in case nobody waits for result System.err.println("DefaultEDT.run(): Catched exception occured on thread "+Thread.currentThread().getName()+": "+task.toString()); diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index 884ddac57..8f792b23c 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -84,7 +84,6 @@ public abstract class DisplayImpl extends Display { if(reuse) { final Display display0 = Display.getLastDisplayOf(type, name, -1, true /* shared only */); if(null != display0) { - display0.setEDTUtil(display0.getEDTUtil()); // ensures EDT is running if(DEBUG) { System.err.println("Display.create() REUSE: "+display0+" "+getThreadName()); } @@ -98,9 +97,9 @@ public abstract class DisplayImpl extends Display { display.id = serialno++; display.fqname = getFQName(display.type, display.name, display.id); display.hashCode = display.fqname.hashCode(); + display.setEDTUtil( display.edtUtil ); // device's default if EDT is used, or null Display.addDisplay2List(display); } - display.setEDTUtil(display.edtUtil); // device's default if EDT is used, or null - ensures EDT is running if(DEBUG) { System.err.println("Display.create() NEW: "+display+" "+getThreadName()); @@ -138,10 +137,10 @@ public abstract class DisplayImpl extends Display { } @Override - public synchronized final void createNative() + public synchronized final void createNative() throws NativeWindowException { - if(null==aDevice) { + if( null == aDevice ) { if(DEBUG) { System.err.println("Display.createNative() START ("+getThreadName()+", "+this+")"); } @@ -154,7 +153,7 @@ public abstract class DisplayImpl extends Display { } catch (Throwable t) { throw new NativeWindowException(t); } - if(null==aDevice) { + if( null == aDevice ) { throw new NativeWindowException("Display.createNative() failed to instanciate an AbstractGraphicsDevice"); } synchronized(displayList) { @@ -180,25 +179,23 @@ public abstract class DisplayImpl extends Display { } @Override - public EDTUtil setEDTUtil(EDTUtil newEDTUtil) { + public synchronized EDTUtil setEDTUtil(final EDTUtil usrEDTUtil) { final EDTUtil oldEDTUtil = edtUtil; - if(null == newEDTUtil) { - if(DEBUG) { - System.err.println("Display.setEDTUtil(default): "+oldEDTUtil+" -> "+newEDTUtil); + final EDTUtil newEDTUtil; + if( null != usrEDTUtil && usrEDTUtil == oldEDTUtil ) { + if( DEBUG ) { + System.err.println("Display.setEDTUtil: "+usrEDTUtil+" - keep!"); } - edtUtil = createEDTUtil(); - } else if( newEDTUtil != edtUtil ) { + newEDTUtil = oldEDTUtil; + } else { if(DEBUG) { - System.err.println("Display.setEDTUtil(custom): "+oldEDTUtil+" -> "+newEDTUtil); + final String msg = ( null == usrEDTUtil ) ? "default" : "custom"; + System.err.println("Display.setEDTUtil("+msg+"): "+oldEDTUtil+" -> "+usrEDTUtil); } - removeEDT( null ); - edtUtil = newEDTUtil; - } else if( DEBUG ) { - System.err.println("Display.setEDTUtil: "+newEDTUtil+" - keep!"); - } - if( !edtUtil.isRunning() ) { // start EDT if not running yet - edtUtil.invoke(true, null); + stopEDT( oldEDTUtil, null ); + newEDTUtil = ( null == usrEDTUtil ) ? createEDTUtil() : usrEDTUtil; } + edtUtil = newEDTUtil; return oldEDTUtil; } @@ -207,29 +204,61 @@ public abstract class DisplayImpl extends Display { return edtUtil; } - private void removeEDT(final Runnable task) { - if(null!=edtUtil) { - edtUtil.invokeStop(true, task); - // ready for restart .. + private static void stopEDT(final EDTUtil edtUtil, final Runnable task) { + if( null != edtUtil ) { + if( edtUtil.isRunning() ) { + final boolean res = edtUtil.invokeStop(true, task); + if( DEBUG ) { + if ( !res ) { + System.err.println("Warning: invokeStop() failed"); + Thread.dumpStack(); + } + } + } edtUtil.waitUntilStopped(); - edtUtil.reset(); - } else { + // ready for restart .. + } else if( null != task ) { task.run(); } } public void runOnEDTIfAvail(boolean wait, final Runnable task) { - if( null!=edtUtil && !edtUtil.isCurrentThreadEDT()) { - edtUtil.invoke(wait, task); + final EDTUtil _edtUtil = edtUtil; + if( null != _edtUtil && !_edtUtil.isCurrentThreadEDT() ) { + if( !_edtUtil.isRunning() ) { // start EDT if not running yet + synchronized( this ) { + if( !_edtUtil.isRunning() ) { // // volatile dbl-checked-locking OK + _edtUtil.restart(); + if( DEBUG ) { + System.err.println("Info: EDT started "+Thread.currentThread().getName()+", "+this); + Thread.dumpStack(); + } + } + } + } + if( !_edtUtil.invoke(wait, task) ) { + if( DEBUG ) { + System.err.println("Warning: invoke(wait "+wait+", ..) on EDT failed .. invoke on current thread "+Thread.currentThread().getName()); + Thread.dumpStack(); + } + task.run(); + } } else { task.run(); } } public boolean validateEDT() { - if(0==refCount && null==aDevice && null != edtUtil && edtUtil.isRunning()) { - removeEDT( null ); - return true; + if( 0==refCount && null == aDevice ) { + final EDTUtil _edtUtil = edtUtil; + if( null != _edtUtil && _edtUtil.isRunning() ) { + synchronized( this ) { + if( null != edtUtil && edtUtil.isRunning() ) { // // volatile dbl-checked-locking OK + stopEDT( edtUtil, null ); + return true; + } + } + } } return false; } @@ -246,17 +275,18 @@ public abstract class DisplayImpl extends Display { if(DEBUG) { System.err.println("Display.destroy(): "+this+", active "+displaysActive+" "+getThreadName()); } - } + } final DisplayImpl f_dpy = this; - removeEDT( new Runnable() { // blocks! + final AbstractGraphicsDevice f_aDevice = aDevice; + aDevice = null; + refCount=0; + stopEDT( edtUtil, new Runnable() { // blocks! public void run() { - if ( null != aDevice ) { - f_dpy.closeNativeImpl(); + if ( null != f_aDevice ) { + f_dpy.closeNativeImpl(f_aDevice); } } } ); - aDevice = null; - refCount=0; if(DEBUG) { dumpDisplayList("Display.destroy("+getFQName()+") END"); } @@ -277,25 +307,28 @@ public abstract class DisplayImpl extends Display { if(0 < displaysActive) { displaysActive--; } + final EDTUtil edtUtil = d.getEDTUtil(); + final AbstractGraphicsDevice f_aDevice = d.aDevice; + d.aDevice = null; + d.refCount=0; final Runnable closeNativeTask = new Runnable() { public void run() { if ( null != d.getGraphicsDevice() ) { - d.closeNativeImpl(); + d.closeNativeImpl(f_aDevice); } } }; - final EDTUtil edtUtil = d.getEDTUtil(); if(null != edtUtil) { final long coopSleep = edtUtil.getPollPeriod() * 2; - edtUtil.invokeStop(false, closeNativeTask); // don't block + if( edtUtil.isRunning() ) { + edtUtil.invokeStop(false, closeNativeTask); // don't block + } try { Thread.sleep( coopSleep < 50 ? coopSleep : 50 ); } catch (InterruptedException e) { } } else { closeNativeTask.run(); } - d.aDevice = null; - d.refCount=0; } } } @@ -331,7 +364,7 @@ public abstract class DisplayImpl extends Display { } protected abstract void createNativeImpl(); - protected abstract void closeNativeImpl(); + protected abstract void closeNativeImpl(AbstractGraphicsDevice aDevice); @Override public final int getId() { @@ -399,15 +432,18 @@ public abstract class DisplayImpl extends Display { @Override public boolean isEDTRunning() { - if(null!=edtUtil) { - return edtUtil.isRunning(); + final EDTUtil _edtUtil = edtUtil; + if( null != _edtUtil ) { + return _edtUtil.isRunning(); } return false; } @Override public String toString() { - return "NEWT-Display["+getFQName()+", excl "+exclusive+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; + final EDTUtil _edtUtil = edtUtil; + final boolean _edtUtilRunning = ( null != _edtUtil ) ? _edtUtil.isRunning() : false; + return "NEWT-Display["+getFQName()+", excl "+exclusive+", refCount "+refCount+", hasEDT "+(null!=_edtUtil)+", edtRunning "+_edtUtilRunning+", "+aDevice+"]"; } /** Dispatch native Toolkit messageges */ @@ -500,17 +536,18 @@ public abstract class DisplayImpl extends Display { } public void enqueueEvent(boolean wait, NEWTEvent e) { - if(!isEDTRunning()) { + final EDTUtil _edtUtil = edtUtil; + if( !_edtUtil.isRunning() ) { // oops .. we are already dead if(DEBUG) { - Throwable t = new Throwable("Warning: EDT already stopped: wait:="+wait+", "+e); - t.printStackTrace(); + System.err.println("Warning: EDT already stopped: wait:="+wait+", "+e); + Thread.dumpStack(); } return; } // can't wait if we are on EDT or NEDT -> consume right away - if(wait && edtUtil.isCurrentThreadEDTorNEDT() ) { + if(wait && _edtUtil.isCurrentThreadEDTorNEDT() ) { dispatchMessage(e); return; } @@ -557,7 +594,7 @@ public abstract class DisplayImpl extends Display { return runWithLockedDevice(device, action); } - protected EDTUtil edtUtil = null; + protected volatile EDTUtil edtUtil = null; protected int id; protected String name; protected String type; diff --git a/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java index a367462c4..a2877dba2 100644 --- a/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java @@ -55,7 +55,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { aDevice.close(); } diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java index abd47d17e..80c72c008 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java @@ -45,7 +45,7 @@ public class AWTEDTUtil implements EDTUtil { private final ThreadGroup threadGroup; private final String name; private final Runnable dispatchMessages; - private NewtEventDispatchThread nedt = null; + private NEDT nedt = null; private int start_iter=0; private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; @@ -53,7 +53,7 @@ public class AWTEDTUtil implements EDTUtil { this.threadGroup = tg; this.name=Thread.currentThread().getName()+"-"+name+"-EDT-"; this.dispatchMessages=dispatchMessages; - this.nedt = new NewtEventDispatchThread(threadGroup, name); + this.nedt = new NEDT(threadGroup, name); this.nedt.setDaemon(true); // don't stop JVM from shutdown .. } @@ -68,33 +68,29 @@ public class AWTEDTUtil implements EDTUtil { } @Override - public final void reset() throws IllegalStateException { + public final boolean restart() throws IllegalStateException { synchronized(edtLock) { - final Thread curT = Thread.currentThread(); - final boolean onAWTEDT = EventQueue.isDispatchThread(); if( nedt.isRunning() ) { - if( !nedt.shouldStop ) { - throw new IllegalStateException("EDT stop not issued."); - } - if( nedt != curT && !onAWTEDT ) { - throw new IllegalStateException("EDT still running: Curr "+curT.getName()+", NEDT "+nedt.getName()+", on AWT-EDT "+onAWTEDT); - } + throw new IllegalStateException("EDT still running and not subject to stop. Curr "+Thread.currentThread().getName()+", NEDT "+nedt.getName()+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", on AWT-EDT "+EventQueue.isDispatchThread()); } if(DEBUG) { System.err.println(Thread.currentThread()+": AWT-EDT reset - edt: "+nedt); } - this.nedt = new NewtEventDispatchThread(threadGroup, name); - this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + if( nedt.getState() != Thread.State.NEW ) { + nedt = new NEDT(threadGroup, name); + nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + startImpl(); } + return invoke(true, nullTask); } private final void startImpl() { if(nedt.isAlive()) { - throw new RuntimeException("AWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); + throw new RuntimeException("AWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", edt: "+nedt); } start_iter++; nedt.setName(name+start_iter); - nedt.shouldStop = false; if(DEBUG) { System.err.println(Thread.currentThread()+": AWT-EDT START - edt: "+nedt); // Thread.dumpStack(); @@ -123,55 +119,72 @@ public class AWTEDTUtil implements EDTUtil { } @Override - public final void invokeStop(boolean wait, Runnable task) { - invokeImpl(wait, task, true); + public final boolean invokeStop(boolean wait, Runnable task) { + return invokeImpl(wait, task, true); } @Override - public final void invoke(boolean wait, Runnable task) { - invokeImpl(wait, task, false); + public final boolean invoke(boolean wait, Runnable task) { + return invokeImpl(wait, task, false); } - private void invokeImpl(boolean wait, Runnable task, boolean stop) { + private static Runnable nullTask = new Runnable() { + @Override + public void run() { } + }; + + private final boolean invokeImpl(boolean wait, Runnable task, boolean stop) { Throwable throwable = null; RunnableTask rTask = null; - Object rTaskLock = new Object(); + final Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution synchronized(edtLock) { // lock the EDT status if( nedt.shouldStop ) { // drop task .. + System.err.println(Thread.currentThread()+": Warning: AWT-EDT about (1) to stop, won't enqueue new task: "+nedt); if(DEBUG) { - System.err.println(Thread.currentThread()+": Warning: AWT-EDT about (1) to stop, won't enqueue new task: "+nedt); Thread.dumpStack(); } - return; + return false; } - // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); - // Thread.dumpStack(); - if(stop) { - synchronized(nedt.sync) { + if( isCurrentThreadEDT() ) { + if(null != task) { + task.run(); + } + wait = false; // running in same thread (EDT) -> no wait + if(stop) { nedt.shouldStop = true; - nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) } - if(DEBUG) { - System.err.println(Thread.currentThread()+": AWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); - // Thread.dumpStack(); + } else { + if( !nedt.isRunning ) { + if( null != task ) { + if( stop ) { + System.err.println(Thread.currentThread()+": Warning: AWT-EDT is about (3) to stop and stopped already, dropping task. NEDT "+nedt); + } else { + System.err.println(Thread.currentThread()+": Warning: AWT-EDT is not running, dropping task. NEDT "+nedt); + } + if(DEBUG) { + Thread.dumpStack(); + } + } + return false; + } else if( stop ) { + if(DEBUG) { + System.err.println(Thread.currentThread()+": AWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop); + } + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } + } + + if(null != task) { + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */, + wait ? null : System.err); + AWTEDTExecutor.singleton.invoke(false, rTask); } - } else if( !nedt.isRunning() ) { - // start if should not stop && not started yet - startImpl(); - } - if( null == task ) { - wait = false; - } else if( isCurrentThreadEDT() ) { - task.run(); - wait = false; // running in same thread (EDT) -> no wait - } else { - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - true /* always catch and report Exceptions, don't disturb EDT */, - wait ? null : System.err); - AWTEDTExecutor.singleton.invoke(false, rTask); } } if( wait ) { @@ -190,51 +203,56 @@ public class AWTEDTUtil implements EDTUtil { throw new RuntimeException(throwable); } } + return true; } } @Override - final public void waitUntilIdle() { - final NewtEventDispatchThread _edt; + final public boolean waitUntilIdle() { + final NEDT _edt; synchronized(edtLock) { _edt = nedt; } - if(!_edt.isRunning() || _edt == Thread.currentThread() || EventQueue.isDispatchThread()) { - return; + if(!_edt.isRunning || _edt == Thread.currentThread() || EventQueue.isDispatchThread()) { + return false; } try { AWTEDTExecutor.singleton.invoke(true, new Runnable() { public void run() { } }); } catch (Exception e) { } + return true; } @Override - final public void waitUntilStopped() { + final public boolean waitUntilStopped() { synchronized(edtLock) { - if( nedt.isRunning() && nedt != Thread.currentThread() && !EventQueue.isDispatchThread() ) { - while(nedt.isRunning()) { + if( nedt.isRunning && nedt != Thread.currentThread() && !EventQueue.isDispatchThread() ) { + while( nedt.isRunning ) { try { edtLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } + return true; + } else { + return false; } } } - class NewtEventDispatchThread extends Thread { + class NEDT extends Thread { volatile boolean shouldStop = false; volatile boolean isRunning = false; Object sync = new Object(); - public NewtEventDispatchThread(ThreadGroup tg, String name) { + public NEDT(ThreadGroup tg, String name) { super(tg, name); } final public boolean isRunning() { - return isRunning; + return isRunning && !shouldStop; } @Override diff --git a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java index 4139951aa..30449f9bc 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java @@ -34,6 +34,8 @@ package jogamp.newt.driver.awt; +import javax.media.nativewindow.AbstractGraphicsDevice; + import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.util.EDTUtil; @@ -65,7 +67,7 @@ public class DisplayDriver extends DisplayImpl { return def; } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { aDevice.close(); } diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java index cc55c336e..112be2b04 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java @@ -69,7 +69,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { aDevice = new EGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, handle, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT, null); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { if (aDevice.getHandle() != EGL.EGL_NO_DISPLAY) { DestroyDisplay(aDevice.getHandle()); } diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java index 08c5c573c..4872a9071 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java @@ -64,7 +64,7 @@ public class DisplayDriver extends DisplayImpl { aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { aDevice.close(); } diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java index e370038d9..ee93eb932 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java @@ -72,7 +72,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { aDevice = new DefaultGraphicsDevice(NativeWindowFactory.TYPE_DEFAULT, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT, displayHandle); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { if(0==displayHandle) { throw new NativeWindowException("displayHandle null; initCnt "+initCounter); } diff --git a/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java index 745be5dae..3cd72e971 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java @@ -64,7 +64,7 @@ public class DisplayDriver extends DisplayImpl { aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { aDevice.close(); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java index b49c6b6e0..a99bc4f23 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java @@ -72,7 +72,7 @@ public class DisplayDriver extends DisplayImpl { aDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { aDevice.close(); } diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java index 1b9ec0f25..595d5e952 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java @@ -76,7 +76,7 @@ public class DisplayDriver extends DisplayImpl { aDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { sharedClassFactory.releaseSharedClass(); aDevice.close(); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java index 88d06f69c..d911483b0 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java @@ -82,13 +82,13 @@ public class DisplayDriver extends DisplayImpl { try { CompleteDisplay0(aDevice.getHandle()); } catch(RuntimeException e) { - closeNativeImpl(); + closeNativeImpl(aDevice); throw e; } } @Override - protected void closeNativeImpl() { + protected void closeNativeImpl(AbstractGraphicsDevice aDevice) { DisplayRelease0(aDevice.getHandle(), javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now javaObjectAtom = 0; windowDeleteAtom = 0; diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java index a8e03c510..d46562050 100644 --- a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java @@ -46,7 +46,7 @@ public class SWTEDTUtil implements EDTUtil { private final String name; private final Runnable dispatchMessages; private final org.eclipse.swt.widgets.Display swtDisplay; - private NewtEventDispatchThread nedt = null; + private NEDT nedt = null; private int start_iter=0; private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; @@ -58,7 +58,7 @@ public class SWTEDTUtil implements EDTUtil { ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages(); } }; this.swtDisplay = swtDisplay; - this.nedt = new NewtEventDispatchThread(threadGroup, name); + this.nedt = new NEDT(threadGroup, name); this.nedt.setDaemon(true); // don't stop JVM from shutdown .. } @@ -77,34 +77,39 @@ public class SWTEDTUtil implements EDTUtil { } @Override - public final void reset() throws IllegalStateException { + public final boolean restart() throws IllegalStateException { + final boolean swtDisposed = swtDisplay.isDisposed(); synchronized(edtLock) { - final Thread curT = Thread.currentThread(); - final Thread swtT = !swtDisplay.isDisposed() ? swtDisplay.getThread() : null; - final boolean onSWTEDT = swtT == curT; if( nedt.isRunning() ) { - if( !nedt.shouldStop ) { - throw new IllegalStateException("EDT stop not issued."); - } - if( nedt != curT && !onSWTEDT ) { - throw new IllegalStateException("EDT still running: Curr "+curT.getName()+", NEDT "+nedt.getName()+", SWT-EDT "+swtT.getName()); - } + final Thread curT = Thread.currentThread(); + final Thread swtT = !swtDisposed ? swtDisplay.getThread() : null; + final boolean onSWTEDT = swtT == curT; + throw new IllegalStateException("EDT still running and not subject to stop. Curr "+curT.getName()+", NEDT "+nedt.getName()+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", SWT-EDT "+swtT.getName()+", on SWT-EDT "+onSWTEDT); } if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt); + System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt+", swtDisposed (skipping) "+swtDisposed); + } + if( !swtDisposed ) { + if( nedt.getState() != Thread.State.NEW ) { + nedt = new NEDT(threadGroup, name); + nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + startImpl(); } - this.nedt = new NewtEventDispatchThread(threadGroup, name); - this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + if( !swtDisposed ) { + return invoke(true, nullTask); + } else { + return false; } } private final void startImpl() { if(nedt.isAlive()) { - throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); + throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", edt: "+nedt); } start_iter++; nedt.setName(name+start_iter); - nedt.shouldStop = false; if(DEBUG) { System.err.println(Thread.currentThread()+": SWT-EDT START - edt: "+nedt); // Thread.dumpStack(); @@ -130,60 +135,89 @@ public class SWTEDTUtil implements EDTUtil { @Override public boolean isRunning() { - return nedt.isRunning() ; + return nedt.isRunning(); } @Override - public final void invokeStop(boolean wait, Runnable task) { - invokeImpl(wait, task, true); + public final boolean invokeStop(boolean wait, Runnable task) { + return invokeImpl(wait, task, true); } @Override - public final void invoke(boolean wait, Runnable task) { - invokeImpl(wait, task, false); + public final boolean invoke(boolean wait, Runnable task) { + return invokeImpl(wait, task, false); } - private void invokeImpl(boolean wait, Runnable task, boolean stop) { + private static Runnable nullTask = new Runnable() { + @Override + public void run() { } + }; + + private final boolean invokeImpl(boolean wait, Runnable task, boolean stop) { Throwable throwable = null; RunnableTask rTask = null; - Object rTaskLock = new Object(); + final Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution synchronized(edtLock) { // lock the EDT status if( nedt.shouldStop ) { // drop task .. if(DEBUG) { - System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt+", isRunning "+nedt.isRunning()); - // Thread.dumpStack(); + System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop); + Thread.dumpStack(); } - return; + return false; } - // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); - // Thread.dumpStack(); - if(stop) { - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt+", isRunning "+nedt.isRunning()); + if( swtDisplay.isDisposed() ) { + stop = true; + } + + if( isCurrentThreadEDT() ) { + if(null != task) { + task.run(); } - synchronized(nedt.sync) { + wait = false; // running in same thread (EDT) -> no wait + if( stop ) { nedt.shouldStop = true; - nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) } - } else if( !nedt.isRunning() && !swtDisplay.isDisposed() ) { - // start if should not stop && not started yet - startImpl(); - } - if( null == task ) { - wait = false; - } else if( swtDisplay.isDisposed() ) { - wait = false; // drop task, SWT disposed - } else if( isCurrentThreadEDT() ) { - task.run(); - wait = false; // running in same thread (EDT) -> no wait - } else { - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - true /* always catch and report Exceptions, don't disturb EDT */, - wait ? null : System.err); - swtDisplay.asyncExec(rTask); + } else { + if( !nedt.isRunning && !swtDisplay.isDisposed() ) { + if( null != task ) { + if( stop ) { + System.err.println(Thread.currentThread()+": Warning: SWT-EDT is about (3) to stop and stopped already, dropping task. NEDT "+nedt); + } else { + System.err.println(Thread.currentThread()+": Warning: SWT-EDT is not running, dropping task. NEDT "+nedt); + } + if(DEBUG) { + Thread.dumpStack(); + } + } + return false; + } else if( stop ) { + if( nedt.isRunning ) { + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop); + } + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } + } + if( swtDisplay.isDisposed() ) { + System.err.println(Thread.currentThread()+": Warning: SWT-EDT is about (3) to stop and stopped already, dropping task. "+nedt); + if(DEBUG) { + Thread.dumpStack(); + } + return false; + } + } + + if( null != task ) { + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */, + wait ? null : System.err); + swtDisplay.asyncExec(rTask); + } } } if( wait ) { @@ -202,55 +236,60 @@ public class SWTEDTUtil implements EDTUtil { throw new RuntimeException(throwable); } } + return true; } } @Override - final public void waitUntilIdle() { - final NewtEventDispatchThread _nedt; + final public boolean waitUntilIdle() { + final NEDT _nedt; synchronized(edtLock) { _nedt = nedt; } final Thread ct = Thread.currentThread(); - if( !_nedt.isRunning() || _nedt == ct || swtDisplay.isDisposed() || swtDisplay.getThread() == ct ) { - return; + if( !_nedt.isRunning || _nedt == ct || swtDisplay.isDisposed() || swtDisplay.getThread() == ct ) { + return false; } try { swtDisplay.syncExec(new Runnable() { public void run() { } }); } catch (Exception e) { } + return true; } @Override - final public void waitUntilStopped() { + final public boolean waitUntilStopped() { synchronized(edtLock) { final Thread curT = Thread.currentThread(); final Thread swtT = !swtDisplay.isDisposed() ? swtDisplay.getThread() : null; final boolean onSWTEDT = swtT == curT; - if( nedt.isRunning() && nedt != curT && !onSWTEDT ) { - while(nedt.isRunning()) { + if( nedt.isRunning && nedt != curT && !onSWTEDT ) { + while( nedt.isRunning ) { try { edtLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } + return true; + } else { + return false; } } } - class NewtEventDispatchThread extends Thread { + class NEDT extends Thread { volatile boolean shouldStop = false; volatile boolean isRunning = false; Object sync = new Object(); - public NewtEventDispatchThread(ThreadGroup tg, String name) { + public NEDT(ThreadGroup tg, String name) { super(tg, name); } final public boolean isRunning() { - return isRunning; + return isRunning && !shouldStop; } @Override -- cgit v1.2.3