diff options
Diffstat (limited to 'src/newt')
-rw-r--r-- | src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java (renamed from src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java) | 157 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/util/EDTUtil.java | 134 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/util/MainThread.java | 35 |
3 files changed, 206 insertions, 120 deletions
diff --git a/src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java index 47c089f87..7a76c94fc 100644 --- a/src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -34,36 +35,38 @@ * facility. */ -package com.jogamp.newt.util; +package com.jogamp.newt.impl; import com.jogamp.common.util.RunnableTask; import com.jogamp.newt.Display; -import com.jogamp.newt.impl.Debug; +import com.jogamp.newt.util.EDTUtil; import java.util.*; public class DefaultEDTUtil implements EDTUtil { public static final boolean DEBUG = Debug.debug("EDT"); private ThreadGroup threadGroup; - private volatile boolean shouldStop = false; private EventDispatchThread edt = null; private Object edtLock = new Object(); // locking the EDT start/stop state - private ArrayList edtTasks = new ArrayList(); // one shot tasks private String name; - private Runnable pumpMessages; + int start_iter=0; + private Runnable dispatchMessages; - public DefaultEDTUtil(ThreadGroup tg, String name, Runnable pumpMessages) { + public DefaultEDTUtil(ThreadGroup tg, String name, Runnable dispatchMessages) { this.threadGroup = tg; - this.name=new String(Thread.currentThread().getName()+"-EDT-"+name); - this.pumpMessages=pumpMessages; - this.edt = new EventDispatchThread(threadGroup, name+"-EDT"); + this.name=new String(Thread.currentThread().getName()+"-"+name+"-EDT-"); + this.dispatchMessages=dispatchMessages; + this.edt = new EventDispatchThread(threadGroup, name); } public final void reset() { synchronized(edtLock) { waitUntilStopped(); - if(edtTasks.size()>0) { - throw new RuntimeException("Remaining EDTTasks: "+edtTasks.size()); + if(edt.tasks.size()>0) { + throw new RuntimeException("Remaining EDTTasks: "+edt.tasks.size()+" - "+edt); + } + if(DEBUG) { + System.err.println(Thread.currentThread()+": EDT reset - edt: "+edt); } this.edt = new EventDispatchThread(threadGroup, name); } @@ -72,24 +75,17 @@ public class DefaultEDTUtil implements EDTUtil { public final void start() { synchronized(edtLock) { if(!edt.isRunning()) { - shouldStop = false; - edt.start(); - if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT START"); + if(edt.isAlive()) { + throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size()); } - } - } - } - - public final void stop() { - synchronized(edtLock) { - if(edt.isRunning()) { - shouldStop = true; + start_iter++; + edt.setName(name+start_iter); + edt.shouldStop = false; if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT signal STOP"); + System.err.println(Thread.currentThread()+": EDT START - edt: "+edt); } + edt.start(); } - edtLock.notifyAll(); } } @@ -98,36 +94,68 @@ public class DefaultEDTUtil implements EDTUtil { } public final boolean isRunning() { - return !shouldStop && edt.isRunning() ; + return edt.isRunning() ; + } + + public final void invokeStop(Runnable task) { + invokeImpl(true, task, true); + } + + public final void invoke(boolean wait, Runnable task) { + invokeImpl(wait, task, false); } - public void invoke(boolean wait, Runnable task) { + private final void invokeImpl(boolean wait, Runnable task, boolean stop) { if(task == null) { - return; + throw new RuntimeException("Null Runnable"); } Throwable throwable = null; RunnableTask rTask = null; Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution - if( isCurrentThreadEDT() ) { - wait = false; - task.run(); - } else { - synchronized(edtLock) { // lock the EDT status + synchronized(edtLock) { // lock the EDT status + if( edt.shouldStop ) { + throw new RuntimeException("EDT about to stop: "+edt); + } + if( isCurrentThreadEDT() ) { + if(stop) { + edt.shouldStop = true; + if(DEBUG) { + System.err.println(Thread.currentThread()+": EDT signal STOP (edt) - edt: "+edt); + } + } + if(!wait && edt.tasks.size()>0) { + // append task to ensure proper sequence + edt.tasks.add(rTask); + } else { + // wait or last task, execute now + task.run(); + } + wait = false; // running in same thread (EDT) -> no wait + if(stop && edt.tasks.size()>0) { + throw new RuntimeException("Remaining EDTTasks: "+edt.tasks.size()+" - "+edt); + } + } else { start(); // start if not started yet - rTask = new RunnableTask(task, wait?rTaskLock:null, true); - synchronized(edtTasks) { - edtTasks.add(rTask); - edtTasks.notifyAll(); + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + wait /* catch Exceptions if waiting for result */); + synchronized(edt.tasks) { + if(stop) { + edt.shouldStop = true; + if(DEBUG) { + System.err.println(Thread.currentThread()+": EDT signal STOP (!edt) - edt: "+edt); + } + } + // append task .. + edt.tasks.add(rTask); + edt.tasks.notifyAll(); } } } - - // wait until task finished, if requested - // and no stop() call slipped through. - if( wait && isRunning() ) { + if( wait ) { try { - rTaskLock.wait(); + rTaskLock.wait(); // free lock, allow execution of rTask } catch (InterruptedException ie) { throwable = ie; } @@ -139,14 +167,17 @@ public class DefaultEDTUtil implements EDTUtil { } } } + if(DEBUG && stop) { + System.err.println(Thread.currentThread()+": EDT signal STOP X edt: "+edt); + } } public void waitUntilIdle() { if(edt.isRunning() && edt != Thread.currentThread()) { - synchronized(edtTasks) { - while(edt.isRunning() && edtTasks.size()>0) { + synchronized(edt.tasks) { + while(edt.isRunning() && edt.tasks.size()>0) { try { - edtTasks.wait(); + edt.tasks.wait(); } catch (InterruptedException e) { e.printStackTrace(); } @@ -170,7 +201,9 @@ public class DefaultEDTUtil implements EDTUtil { } class EventDispatchThread extends Thread { + volatile boolean shouldStop = false; volatile boolean isRunning = false; + ArrayList tasks = new ArrayList(); // one shot tasks public EventDispatchThread(ThreadGroup tg, String name) { super(tg, name); @@ -186,55 +219,61 @@ public class DefaultEDTUtil implements EDTUtil { } /** - * Utilizing locking only on edtTasks and its execution, + * Utilizing locking only on tasks and its execution, * not for event dispatching. */ public void run() { if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT run() START"); + System.err.println(getName()+": EDT run() START "+ getName()); } try { do { // event dispatch if(!shouldStop) { - pumpMessages.run(); + dispatchMessages.run(); } // wait and work on tasks Runnable task = null; - synchronized(edtTasks) { + synchronized(tasks) { // wait for tasks - while(!shouldStop && edtTasks.size()==0) { + if(!shouldStop && tasks.size()==0) { try { - edtTasks.wait(defaultEDTPollGranularity); + tasks.wait(defaultEDTPollGranularity); } catch (InterruptedException e) { e.printStackTrace(); } } // execute one task, if available - if(edtTasks.size()>0) { - task = (Runnable) edtTasks.remove(0); - edtTasks.notifyAll(); + if(tasks.size()>0) { + task = (Runnable) tasks.remove(0); + tasks.notifyAll(); } } if(null!=task) { task.run(); } - } while(!shouldStop || edtTasks.size()>0) ; + } while(!shouldStop) ; } catch (Throwable t) { // handle errors .. shouldStop = true; - throw new RuntimeException(t); + throw new RuntimeException(getName()+": EDT run() Error", t); } finally { - // check for tasks - // sync for waitUntilStopped() + if(DEBUG) { + System.err.println(getName()+": EDT run() END "+ getName()); + } synchronized(edtLock) { + synchronized(tasks) { + if(tasks.size()>0) { + throw new RuntimeException("Remaining EDTTasks: "+tasks.size()+" - "+edt); + } + } isRunning = !shouldStop; if(!isRunning) { edtLock.notifyAll(); } } if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT run() EXIT"); + System.err.println(getName()+": EDT run() EXIT "+ getName()); } } } diff --git a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java index 969da6c2d..d1a11a788 100644 --- a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java @@ -1,76 +1,114 @@ -/* - * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution 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. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. +/** + * Copyright 2010 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 com.jogamp.newt.util; -import com.jogamp.common.util.RunnableTask; -import com.jogamp.newt.Display; -import java.util.*; - +/** + * EDT stands for Event Dispatch Thread. + * <p> + * EDTUtil comprises the functionality of: + * <ul> + * <li> Periodically issuing an event dispatch command on the EDT.</li> + * <li> Ability to enqueue tasks, executed on the EDT.</li> + * <li> Controlling the EDT, ie start and stop in a sane manner.</li> + * </ul> + * The EDT pattern is a common tool to comply with todays windowing toolkits, + * where the common denominator in regards to multithreading is to: + * <ul> + * <li> Create a Window on one thread </li> + * <li> Modify the Window within the same thread </li> + * <li> Handle incoming events from within the same thread </li> + * </ul> + * Note: This is not true on MacOSX, where all these actions have to be + * performed by a unique, so called main thread.<br> + */ public interface EDTUtil { public static final long defaultEDTPollGranularity = 10; // 10ms, 1/100s + /** + * Create a new EDT. One should invoke <code>reset()</code><br> + * after <code>invokeStop(..)</code> in case another <code>start()</code> or <code>invoke(..)</code> + * is expected. + * + * @see #start() + * @see #invoke(boolean, java.lang.Runnable) + * @see #invokeStop(java.lang.Runnable) + */ public void reset(); + /** + * Start the EDT + */ public void start(); - public void stop(); - + /** + * @return True if the current thread is the EDT thread + */ public boolean isCurrentThreadEDT(); + /** + * @return True if EDT is running + */ public boolean isRunning(); /** - * Add task to the EDT task queue. - * Wait until execution is finished if wait is true. - * Shall start the thread if not running + * Append the final task to the EDT task queue, + * signals EDT to stop and wait until stopped.<br> + * Due to the nature of this method: + * <ul> + * <li>All previous queued tasks will be finished.</li> + * <li>No new tasks are allowed, an Exception is thrown.</li> + * <li>Can be issued from within EDT, ie from within an enqueued task.</li> + * <li>{@link #reset()} may follow immediately, ie creating a new EDT</li> + * </ul> + */ + public void invokeStop(Runnable finalTask); + + /** + * Append task to the EDT task queue.<br> + * Wait until execution is finished if <code>wait == true</code>.<br> + * Shall start the thread if not running.<br> + * Can be issued from within EDT, ie from within an enqueued task.<br> + * + * @throws RuntimeException in case EDT is stopped and not {@link #reset()} */ public void invoke(boolean wait, Runnable task); /** - * Wait until EDT task queue, filled via invoke, is empty. - * It is allowed that the last task is still in execution - * when this method returns. + * Wait until the EDT task queue is empty.<br> + * The last task may still be in execution when this method returns. */ public void waitUntilIdle(); /** - * Wait until EDT task has stopped. - * stop is not exected here and should be beforehand. + * Wait until EDT task is stopped.<br> + * No <code>stop</code> action is performed, {@link #invokeStop(java.lang.Runnable)} should be used before. */ public void waitUntilStopped(); } diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java index cb5c87a89..5b26cfbda 100644 --- a/src/newt/classes/com/jogamp/newt/util/MainThread.java +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -148,7 +149,10 @@ public class MainThread implements EDTUtil { if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin"); if ( useMainThread ) { - singletonMainThread.stop(); + singletonMainThread.invokeStop(new Runnable() { + public void run() { + // nop + }}); if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainThread fin - stop"); System.exit(0); } @@ -251,17 +255,6 @@ public class MainThread implements EDTUtil { // nop } - public void stop() { - if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" start"); - synchronized(taskWorkerLock) { - if(isRunning) { - shouldStop = true; - } - taskWorkerLock.notifyAll(); - } - if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" end"); - } - public boolean isCurrentThreadEDT() { if(NativeWindowFactory.isAWTAvailable()) { initAWTReflection(); @@ -291,8 +284,15 @@ public class MainThread implements EDTUtil { } } - /** invokes the given Runnable */ + public void invokeStop(Runnable r) { + invokeImpl(true, r, true); + } + public void invoke(boolean wait, Runnable r) { + invokeImpl(wait, r, false); + } + + private void invokeImpl(boolean wait, Runnable r, boolean stop) { if(r == null) { return; } @@ -319,6 +319,7 @@ public class MainThread implements EDTUtil { // if this main thread is not being used or // if this is already the main thread .. just execute. + // FIXME: start if not started .. sync logic with DefaultEDTUtil!!! if( !isRunning() || mainThread == Thread.currentThread() ) { r.run(); return; @@ -330,6 +331,14 @@ public class MainThread implements EDTUtil { Throwable throwable = null; synchronized(lock) { invokeLater(rTask); + // FIXME .. + synchronized(taskWorkerLock) { + if(isRunning) { + shouldStop = true; + if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" start"); + } + taskWorkerLock.notifyAll(); + } if( doWait ) { try { lock.wait(); |