summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-09-12 17:29:31 +0200
committerSven Gothel <[email protected]>2015-09-12 17:29:31 +0200
commit2b97ed6d238a0db1e2cf7bdf15349e90eaaa8dfc (patch)
treeaf8429652c07fae310cd2b85921667126019904f
parent47495cd2a228534578731346c8baf2b190bcd241 (diff)
Bug 1213 (related): Fix TaskBase, RunnableTask and FunctionTask implementation and semantics
- TaskBase - requires 'volatile boolean isExecuted' for atomic query of same semantics - fix isInQueue(): condition was reverse in regars to 'isExecuted' - expose 'Thread getExecutionThread()' as learned within run() method. - RunnableTask - deprecate: 'static invoke(final boolean waitUntilDone, final Runnable runnable)', since it's nonsense, use runnable.run() instead. - 'static RunnableTask invokeOnNewThread(..)' - uses InterruptSource.Thread - Persistent-Wait - Cancelable using InterruptedRuntimeException - FunctionTask - deprecate 'static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args)', since it's nonsense, use func.eval(args) instead. - 'static FunctionTask<U,V> invokeOnNewThread(..)' - uses InterruptSource.Thread - Persistent-Wait - Cancelable using InterruptedRuntimeException
-rw-r--r--src/java/com/jogamp/common/util/FunctionTask.java68
-rw-r--r--src/java/com/jogamp/common/util/RunnableTask.java90
-rw-r--r--src/java/com/jogamp/common/util/TaskBase.java15
3 files changed, 101 insertions, 72 deletions
diff --git a/src/java/com/jogamp/common/util/FunctionTask.java b/src/java/com/jogamp/common/util/FunctionTask.java
index 4ac64d3..5a58a34 100644
--- a/src/java/com/jogamp/common/util/FunctionTask.java
+++ b/src/java/com/jogamp/common/util/FunctionTask.java
@@ -30,6 +30,8 @@ package com.jogamp.common.util;
import java.io.PrintStream;
+import com.jogamp.common.JogampRuntimeException;
+
/**
* Helper class to provide a Runnable queue implementation with a Runnable wrapper
* which notifies after execution for the <code>invokeAndWait()</code> semantics.
@@ -40,34 +42,54 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
protected A[] args;
/**
- * Invokes <code>func</code>.
+ * @deprecated Simply invoke {@link Function#eval(Object...)}
+ */
+ public static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args) {
+ return func.eval(args);
+ }
+
+ /**
+ * Invokes <code>func</code> on a new thread belonging to the given {@link ThreadGroup}.
+ * <p>
+ * The result can be retrieved via {@link FunctionTask#getResult()},
+ * using the returned instance.
+ * </p>
+ * @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code>
+ * @param threadName the name for the new thread
* @param waitUntilDone if <code>true</code>, waits until <code>func</code> execution is completed, otherwise returns immediately.
* @param func the {@link Function} to execute.
* @param args the {@link Function} arguments
- * @return the {@link Function} return value
+ * @return the newly created and invoked {@link FunctionTask}
*/
- public static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args) {
- Throwable throwable = null;
- final Object sync = new Object();
- final FunctionTask<U,V> rt = new FunctionTask<U,V>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
- final U res;
- synchronized(sync) {
- res = rt.eval(args);
- if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
+ public static <U,V> FunctionTask<U,V> invokeOnNewThread(final ThreadGroup tg, final String threadName,
+ final boolean waitUntilDone, final Function<U,V> func, final V... args) {
+ final FunctionTask<U,V> rt;
+ if( !waitUntilDone ) {
+ rt = new FunctionTask<U,V>( func, null, true, System.err );
+ final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName);
+ rt.args = args;
+ t.start();
+ } else {
+ final Object sync = new Object();
+ rt = new FunctionTask<U,V>( func, sync, true, null );
+ final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName);
+ synchronized(sync) {
+ rt.args = args;
+ t.start();
+ while( rt.isInQueue() ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ final Throwable throwable = rt.getThrowable();
+ if(null!=throwable) {
+ throw new JogampRuntimeException(throwable);
+ }
}
}
}
- return res;
+ return rt;
}
/**
@@ -124,6 +146,8 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
*/
@Override
public final void run() {
+ execThread = Thread.currentThread();
+
final A[] args = this.args;
this.args = null;
this.result = null;
@@ -144,6 +168,7 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
}
} else {
synchronized (syncObject) {
@@ -161,6 +186,7 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
syncObject.notifyAll();
}
}
diff --git a/src/java/com/jogamp/common/util/RunnableTask.java b/src/java/com/jogamp/common/util/RunnableTask.java
index 6fb98de..69d7af2 100644
--- a/src/java/com/jogamp/common/util/RunnableTask.java
+++ b/src/java/com/jogamp/common/util/RunnableTask.java
@@ -30,6 +30,8 @@ package com.jogamp.common.util;
import java.io.PrintStream;
+import com.jogamp.common.JogampRuntimeException;
+
/**
* Helper class to provide a Runnable queue implementation with a Runnable wrapper
* which notifies after execution for the <code>invokeAndWait()</code> semantics.
@@ -38,30 +40,18 @@ public class RunnableTask extends TaskBase {
protected final Runnable runnable;
/**
- * Invokes <code>runnable</code> on the current thread.
- * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately.
- * @param runnable the {@link Runnable} to execute.
+ * @deprecated Simply invoke {@link Runnable#run()}
*/
public static void invoke(final boolean waitUntilDone, final Runnable runnable) {
- Throwable throwable = null;
- final Object sync = new Object();
- final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
- synchronized(sync) {
- rt.run();
- if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
- }
- }
- }
+ runnable.run();
+ }
+
+ /**
+ * @deprecated Use {@link #invokeOnNewThread(ThreadGroup, String, boolean, Runnable)}
+ */
+ public static Thread invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable, final String threadName) {
+ final RunnableTask rt = invokeOnNewThread(tg, threadName, waitUntilDone, runnable);
+ return rt.getExecutionThread();
}
/**
@@ -71,37 +61,37 @@ public class RunnableTask extends TaskBase {
* @param runnable the {@link Runnable} to execute on the new thread. If <code>waitUntilDone</code> is <code>true</code>,
* the runnable <b>must exist</b>, i.e. not loop forever.
* @param threadName the name for the new thread
- * @return the newly created {@link Thread}
+ * @return the newly created and invoked {@link RunnableTask}
*/
- public static Thread invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable, final String threadName) {
- final Thread t = new Thread(tg, threadName) {
- @Override
- public void run() {
- Throwable throwable = null;
- final Object sync = new Object();
- final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
- synchronized(sync) {
- rt.run();
- if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
- }
+ public static RunnableTask invokeOnNewThread(final ThreadGroup tg, final String threadName,
+ final boolean waitUntilDone, final Runnable runnable) {
+ final RunnableTask rt;
+ if( !waitUntilDone ) {
+ rt = new RunnableTask( runnable, null, true, System.err );
+ final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName);
+ t.start();
+ } else {
+ final Object sync = new Object();
+ rt = new RunnableTask( runnable, sync, true, null );
+ final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName);
+ synchronized(sync) {
+ t.start();
+ while( rt.isInQueue() ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ final Throwable throwable = rt.getThrowable();
+ if(null!=throwable) {
+ throw new JogampRuntimeException(throwable);
}
}
- } };
- t.start();
- return t;
+ }
+ }
+ return rt;
}
-
/**
* Create a RunnableTask object w/ synchronization,
* ie. suitable for <code>invokeAndWait()</code>, i.e. {@link #invoke(boolean, Runnable) invoke(true, runnable)}.
@@ -126,6 +116,8 @@ public class RunnableTask extends TaskBase {
@Override
public final void run() {
+ execThread = Thread.currentThread();
+
runnableException = null;
tStarted = System.currentTimeMillis();
if(null == syncObject) {
@@ -143,6 +135,7 @@ public class RunnableTask extends TaskBase {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
}
} else {
synchronized (syncObject) {
@@ -160,6 +153,7 @@ public class RunnableTask extends TaskBase {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
syncObject.notifyAll();
}
}
diff --git a/src/java/com/jogamp/common/util/TaskBase.java b/src/java/com/jogamp/common/util/TaskBase.java
index 59b86c3..518aeba 100644
--- a/src/java/com/jogamp/common/util/TaskBase.java
+++ b/src/java/com/jogamp/common/util/TaskBase.java
@@ -54,7 +54,9 @@ public abstract class TaskBase implements Runnable {
protected Throwable runnableException;
protected long tCreated, tStarted;
protected volatile long tExecuted;
+ protected volatile boolean isExecuted;
protected volatile boolean isFlushed;
+ protected volatile Thread execThread;
protected TaskBase(final Object syncObject, final boolean catchExceptions, final PrintStream exceptionOut) {
this.syncObject = syncObject;
@@ -64,7 +66,9 @@ public abstract class TaskBase implements Runnable {
tCreated = System.currentTimeMillis();
tStarted = 0;
tExecuted = 0;
+ isExecuted = false;
isFlushed = false;
+ execThread = null;
}
protected final String getExceptionOutIntro() {
@@ -76,6 +80,11 @@ public abstract class TaskBase implements Runnable {
}
}
+ /** Returns the execution thread or {@code null} if not yet {@link #run()}. */
+ public final Thread getExecutionThread() {
+ return execThread;
+ }
+
/**
* Return the synchronization object if any.
* @see #RunnableTask(Runnable, Object, boolean)
@@ -126,12 +135,12 @@ public abstract class TaskBase implements Runnable {
/**
* @return !{@link #isExecuted()} && !{@link #isFlushed()}
*/
- public final boolean isInQueue() { return 0 != tExecuted && !isFlushed; }
+ public final boolean isInQueue() { return !isExecuted() && !isFlushed(); }
/**
* @return True if executed, otherwise false;
*/
- public final boolean isExecuted() { return 0 != tExecuted ; }
+ public final boolean isExecuted() { return isExecuted; }
/**
* @return True if flushed, otherwise false;
@@ -159,7 +168,7 @@ public abstract class TaskBase implements Runnable {
@Override
public String toString() {
- return "RunnableTask[executed "+isExecuted()+", tTotal "+getDurationTotal()+" ms, tExec "+getDurationInExec()+" ms, tQueue "+getDurationInQueue()+" ms, attachment "+attachment+", throwable "+getThrowable()+"]";
+ return "RunnableTask[enqueued "+isInQueue()+"[executed "+isExecuted()+", flushed "+isFlushed()+"], tTotal "+getDurationTotal()+" ms, tExec "+getDurationInExec()+" ms, tQueue "+getDurationInQueue()+" ms, attachment "+attachment+", throwable "+getThrowable()+"]";
}
}