diff options
author | Sven Gothel <[email protected]> | 2013-02-13 13:04:27 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-02-13 13:04:27 +0100 |
commit | b387d012103a02eb7d5eb919306583295ef09a38 (patch) | |
tree | 2e01b804cc071e0350ec72059cbd470d23c596e0 /src | |
parent | 30841742e735e70b3946d16711089960084e894c (diff) |
Adding Function and FunctionTask extending RunnableTask functionality
Function allows passing arguments and having a return value in contrast to Runnable,
where FunctionTask allows a Function to be invoked and waited for.
Diffstat (limited to 'src')
-rw-r--r-- | src/java/com/jogamp/common/util/Function.java | 49 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/FunctionTask.java | 160 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/RunnableTask.java | 151 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/TaskBase.java | 137 |
4 files changed, 379 insertions, 118 deletions
diff --git a/src/java/com/jogamp/common/util/Function.java b/src/java/com/jogamp/common/util/Function.java new file mode 100644 index 0000000..8bec99c --- /dev/null +++ b/src/java/com/jogamp/common/util/Function.java @@ -0,0 +1,49 @@ +/** + * Copyright 2013 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.common.util; + +/** + * Generic function interface to perform an action w/ given optional arguments + * producing an optional result. + * <p> + * For <code>void</code> functions, simply use type <code>Object</code> + * and ignore the result and/or arguments. + * </p> + * + * @param <T> the result type of {@link #eval(Object...)} + */ +public interface Function<R,A> { + /** + * Implementation may compute variable <code>args</code> list + * and returns a result. + * + * @param args variable argument list, <code>A[]</code>, maybe null + * @return the result. + */ + R eval(A... args); +} diff --git a/src/java/com/jogamp/common/util/FunctionTask.java b/src/java/com/jogamp/common/util/FunctionTask.java new file mode 100644 index 0000000..8a1ef44 --- /dev/null +++ b/src/java/com/jogamp/common/util/FunctionTask.java @@ -0,0 +1,160 @@ +/** + * Copyright 2013 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.common.util; + +/** + * Helper class to provide a Runnable queue implementation with a Runnable wrapper + * which notifies after execution for the <code>invokeAndWait()</code> semantics. + */ +public class FunctionTask<R,A> extends TaskBase implements Function<R,A> { + protected Function<R,A> runnable; + protected R result; + protected A[] args; + + /** + * Invokes <code>func</code>. + * @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 + */ + public static <U,V> U invoke(boolean waitUntilDone, Function<U,V> func, V... args) { + Throwable throwable = null; + final Object sync = new Object(); + final FunctionTask<U,V> rt = new FunctionTask<U,V>( func, waitUntilDone ? sync : null, true ); + final U res; + synchronized(sync) { + res = rt.eval(args); + if( waitUntilDone ) { + try { + sync.wait(); + } catch (InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rt.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + return res; + } + + /** + * Create a RunnableTask object w/ synchronization, + * ie. suitable for <code>invokeAndWait()</code>. + * + * @param runnable the user action + * @param syncObject the synchronization object the caller shall wait until <code>runnable</code> execution is completed, + * or <code>null</code> if waiting is not desired. + * @param catchExceptions if true, exception during <code>runnable</code> execution are catched, otherwise not. + * Use {@link #getThrowable()} to determine whether an exception has been catched. + */ + public FunctionTask(Function<R,A> runnable, Object syncObject, boolean catchExceptions) { + super(syncObject, catchExceptions); + this.runnable = runnable ; + result = null; + args = null; + } + + /** Return the user action */ + public Function<R,A> getRunnable() { + return runnable; + } + + /** + * Sets the arguments for {@link #run()}. + * They will be cleared afterwards. + */ + public void setArgs(A... args) { + this.args = args; + } + + /** + * Retrieves the cached result of {@link #run()} + * and clears it afterwards. + */ + public R getResult() { + final R res = result; + result = null; + return res; + } + + /** + * {@inheritDoc} + * <p> + * Calls {@link #eval(Object...)}. + * </p> + * <p> + * You may set the {@link #eval(Object...)} arguments via {@link #setArgs(Object...)} + * and retrieve the result via {@link #getResult()}. + * </p> + */ + @Override + public void run() { + result = eval(args); + args = null; + } + + @Override + public R eval(A... args) { + R res = null; + tStarted = System.currentTimeMillis(); + if(null == syncObject) { + try { + res = runnable.eval(args); + } catch (Throwable t) { + runnableException = t; + if(!catchExceptions) { + throw new RuntimeException(runnableException); + } + } finally { + tExecuted = System.currentTimeMillis(); + } + } else { + synchronized (syncObject) { + try { + res = runnable.eval(args); + } catch (Throwable t) { + runnableException = t; + if(!catchExceptions) { + throw new RuntimeException(runnableException); + } + } finally { + tExecuted = System.currentTimeMillis(); + syncObject.notifyAll(); + } + } + } + return res; + } +} + diff --git a/src/java/com/jogamp/common/util/RunnableTask.java b/src/java/com/jogamp/common/util/RunnableTask.java index b0ce159..6a4ccb3 100644 --- a/src/java/com/jogamp/common/util/RunnableTask.java +++ b/src/java/com/jogamp/common/util/RunnableTask.java @@ -32,55 +32,49 @@ package com.jogamp.common.util; * Helper class to provide a Runnable queue implementation with a Runnable wrapper * which notifies after execution for the <code>invokeAndWait()</code> semantics. */ -public class RunnableTask implements Runnable { - Runnable runnable; - final Object syncObject; - boolean catchExceptions; - Object attachment; - - Throwable runnableException; - long tCreated, tStarted; - volatile long tExecuted; - volatile boolean isFlushed; - - /** - * Create a RunnableTask object w/o synchronization, - * ie. not suitable for <code>invokeAndWait()</code>. - * - * @param runnable the user action - */ - public RunnableTask(Runnable runnable) { - this(runnable, null, false); - } +public class RunnableTask extends TaskBase { + protected final Runnable runnable; /** - * Create a RunnableTask object w/ synchronization, - * ie. suitable for <code>invokeAndWait()</code>. - * - * @param runnable the user action - * @param syncObject the synchronization object the caller shall wait for in case of <code>invokeAndWait()</code> + * Invoks <code>runnable</code>. + * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately. + * @param runnable the {@link Runnable} to execute. */ - public RunnableTask(Runnable runnable, Object syncObject) { - this(runnable, syncObject, false); + public static void invoke(boolean waitUntilDone, Runnable runnable) { + Throwable throwable = null; + final Object sync = new Object(); + final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true ); + synchronized(sync) { + rt.run(); + if( waitUntilDone ) { + try { + sync.wait(); + } catch (InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rt.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } } - + /** * Create a RunnableTask object w/ synchronization, - * ie. suitable for <code>invokeAndWait()</code>. + * ie. suitable for <code>invokeAndWait()</code>, i.e. {@link #invoke(boolean, Runnable) invoke(true, runnable)}. * * @param runnable the user action - * @param syncObject the synchronization object the caller shall wait for in case of <code>invokeAndWai()t</code> + * @param syncObject the synchronization object if caller wait until <code>runnable</code> execution is completed, + * or <code>null</code> if waiting is not desired. * @param catchExceptions if true, exception during <code>runnable</code> execution are catched, otherwise not. * Use {@link #getThrowable()} to determine whether an exception has been catched. */ public RunnableTask(Runnable runnable, Object syncObject, boolean catchExceptions) { + super(syncObject, catchExceptions); this.runnable = runnable ; - this.syncObject = syncObject ; - this.catchExceptions = catchExceptions ; - tCreated = System.currentTimeMillis(); - tStarted = 0; - tExecuted = 0; - isFlushed = false; } /** Return the user action */ @@ -88,30 +82,7 @@ public class RunnableTask implements Runnable { return runnable; } - /** - * Return the synchronization object if any. - * @see #RunnableTask(Runnable, Object, boolean) - */ - public Object getSyncObject() { - return syncObject; - } - - /** - * Attach a custom object to this task. - * Useful to piggybag further information, ie tag a task final. - */ - public void setAttachment(Object o) { - attachment = o; - } - - /** - * Return the attachment object if any. - * @see #setAttachment(Object) - */ - public Object getAttachment() { - return attachment; - } - + @Override public void run() { tStarted = System.currentTimeMillis(); if(null == syncObject) { @@ -139,63 +110,7 @@ public class RunnableTask implements Runnable { syncObject.notifyAll(); } } - } - } - - /** - * Simply flush this task and notify a waiting executor. - * The executor which might have been blocked until notified - * will be unblocked and the task removed from the queue. - * - * @see #isFlushed() - * @see #isInQueue() - */ - public void flush() { - if(!isExecuted() && hasWaiter()) { - synchronized (syncObject) { - isFlushed = true; - syncObject.notifyAll(); - } - } - } - - /** - * @return !{@link #isExecuted()} && !{@link #isFlushed()} - */ - public boolean isInQueue() { return 0 != tExecuted && !isFlushed; } - - /** - * @return True if executed, otherwise false; - */ - public boolean isExecuted() { return 0 != tExecuted ; } - - /** - * @return True if flushed, otherwise false; - */ - public boolean isFlushed() { return isFlushed; } - - /** - * @return True if invoking thread waits until done, - * ie a <code>notifyObject</code> was passed, otherwise false; - */ - public boolean hasWaiter() { return null != syncObject; } - - /** - * @return A thrown exception while execution of the user action, if any and if catched - * @see #RunnableTask(Runnable, Object, boolean) - */ - public Throwable getThrowable() { return runnableException; } - - public long getTimestampCreate() { return tCreated; } - public long getTimestampBeforeExec() { return tStarted; } - public long getTimestampAfterExec() { return tExecuted; } - public long getDurationInQueue() { return tStarted - tCreated; } - public long getDurationInExec() { return tExecuted - tStarted; } - public long getDurationTotal() { return tExecuted - tCreated; } - - @Override - public String toString() { - return "RunnableTask[executed "+isExecuted()+", t2-t0 "+getDurationTotal()+", t2-t1 "+getDurationInExec()+", t1-t0 "+getDurationInQueue()+", throwable "+getThrowable()+", Runnable "+runnable+", Attachment "+attachment+"]"; - } + } + } } diff --git a/src/java/com/jogamp/common/util/TaskBase.java b/src/java/com/jogamp/common/util/TaskBase.java new file mode 100644 index 0000000..e9366c2 --- /dev/null +++ b/src/java/com/jogamp/common/util/TaskBase.java @@ -0,0 +1,137 @@ +/** + * 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.common.util; + +/** + * Helper class to provide a Runnable queue implementation with a Runnable wrapper + * which notifies after execution for the <code>invokeAndWait()</code> semantics. + */ +public abstract class TaskBase implements Runnable { + protected final Object syncObject; + protected final boolean catchExceptions; + + protected Object attachment; + protected Throwable runnableException; + protected long tCreated, tStarted; + protected volatile long tExecuted; + protected volatile boolean isFlushed; + + protected TaskBase(Object syncObject, boolean catchExceptions) { + this.syncObject = syncObject ; + this.catchExceptions = catchExceptions ; + tCreated = System.currentTimeMillis(); + tStarted = 0; + tExecuted = 0; + isFlushed = false; + } + + /** + * Return the synchronization object if any. + * @see #RunnableTask(Runnable, Object, boolean) + */ + public Object getSyncObject() { + return syncObject; + } + + /** + * Attach a custom object to this task. + * Useful to piggybag further information, ie tag a task final. + */ + public void setAttachment(Object o) { + attachment = o; + } + + /** + * Return the attachment object if any. + * @see #setAttachment(Object) + */ + public Object getAttachment() { + return attachment; + } + + @Override + public abstract void run(); + + /** + * Simply flush this task and notify a waiting executor. + * The executor which might have been blocked until notified + * will be unblocked and the task removed from the queue. + * + * @see #isFlushed() + * @see #isInQueue() + */ + public void flush() { + if(!isExecuted() && hasWaiter()) { + synchronized (syncObject) { + isFlushed = true; + syncObject.notifyAll(); + } + } + } + + /** + * @return !{@link #isExecuted()} && !{@link #isFlushed()} + */ + public boolean isInQueue() { return 0 != tExecuted && !isFlushed; } + + /** + * @return True if executed, otherwise false; + */ + public boolean isExecuted() { return 0 != tExecuted ; } + + /** + * @return True if flushed, otherwise false; + */ + public boolean isFlushed() { return isFlushed; } + + /** + * @return True if invoking thread waits until done, + * ie a <code>notifyObject</code> was passed, otherwise false; + */ + public boolean hasWaiter() { return null != syncObject; } + + /** + * @return A thrown exception while execution of the user action, if any and if catched + * @see #RunnableTask(Runnable, Object, boolean) + */ + public Throwable getThrowable() { return runnableException; } + + public long getTimestampCreate() { return tCreated; } + public long getTimestampBeforeExec() { return tStarted; } + public long getTimestampAfterExec() { return tExecuted; } + public long getDurationInQueue() { return tStarted - tCreated; } + public long getDurationInExec() { return tExecuted - tStarted; } + public long getDurationTotal() { return tExecuted - tCreated; } + + @Override + public String toString() { + return "RunnableTask[executed "+isExecuted()+", t2-t0 "+getDurationTotal()+", t2-t1 "+getDurationInExec()+", t1-t0 "+getDurationInQueue()+", throwable "+getThrowable()+", Attachment "+attachment+"]"; + } +} + |