summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-09-15 05:12:14 +0200
committerSven Gothel <[email protected]>2015-09-15 05:12:14 +0200
commit1c4e2d3ea379fe6578dfb84e10f22729b71b1ae5 (patch)
tree6bcd646a474bcf0c79043fe2520ccaa51a57eea1 /src
parent2b97ed6d238a0db1e2cf7bdf15349e90eaaa8dfc (diff)
Bug 1213: Refine changes .. comments and API
- Use InterruptSource.Thread.create(..), while reducing InterruptSource.Thread ctors to 3 variants. - Use InterruptSource.Thread instead of java.lang.Thread where possible - Use SourcedInterruptedException where possible - SingletonInstanceServerSocket: start(), stop() and run() - Persistent-Wait and Cancelable - Add @since 2.3.2
Diffstat (limited to 'src')
-rw-r--r--src/java/com/jogamp/common/util/FunctionTask.java10
-rw-r--r--src/java/com/jogamp/common/util/InterruptSource.java43
-rw-r--r--src/java/com/jogamp/common/util/RunnableTask.java12
-rw-r--r--src/java/com/jogamp/common/util/SourcedInterruptedException.java1
-rw-r--r--src/java/com/jogamp/common/util/TaskBase.java7
-rw-r--r--src/java/com/jogamp/common/util/cache/TempFileCache.java5
-rw-r--r--src/java/jogamp/android/launcher/LauncherTempFileCache.java6
-rw-r--r--src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java3
-rw-r--r--src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java127
-rw-r--r--src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java3
-rw-r--r--src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java3
11 files changed, 144 insertions, 76 deletions
diff --git a/src/java/com/jogamp/common/util/FunctionTask.java b/src/java/com/jogamp/common/util/FunctionTask.java
index 5a58a34..630ae2f 100644
--- a/src/java/com/jogamp/common/util/FunctionTask.java
+++ b/src/java/com/jogamp/common/util/FunctionTask.java
@@ -49,30 +49,32 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
}
/**
- * Invokes <code>func</code> on a new thread belonging to the given {@link ThreadGroup}.
+ * Invokes <code>func</code> on a new {@link InterruptSource.Thread},
+ * see {@link InterruptSource.Thread#Thread(ThreadGroup, Runnable, String)} for details.
* <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 threadName the name for the new thread, maybe <code>null</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 newly created and invoked {@link FunctionTask}
+ * @since 2.3.2
*/
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);
+ final InterruptSource.Thread t = InterruptSource.Thread.create(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);
+ final InterruptSource.Thread t = InterruptSource.Thread.create(tg, rt, threadName);
synchronized(sync) {
rt.args = args;
t.start();
diff --git a/src/java/com/jogamp/common/util/InterruptSource.java b/src/java/com/jogamp/common/util/InterruptSource.java
index 1d43961..01fcdb5 100644
--- a/src/java/com/jogamp/common/util/InterruptSource.java
+++ b/src/java/com/jogamp/common/util/InterruptSource.java
@@ -31,6 +31,7 @@ package com.jogamp.common.util;
/**
* Interface exposing {@link java.lang.Thread#interrupt()} source,
* intended for {@link java.lang.Thread} specializations.
+ * @since 2.3.2
*/
public interface InterruptSource {
/**
@@ -52,7 +53,7 @@ public interface InterruptSource {
public static class Util {
/**
- * Casts given {@link java.lang.Thread} to {@link InterruptSource},
+ * Casts given {@link java.lang.Thread} to {@link InterruptSource}
* if applicable, otherwise returns {@code null}.
*/
public static InterruptSource get(final java.lang.Thread t) {
@@ -63,7 +64,7 @@ public interface InterruptSource {
}
}
/**
- * Casts current {@link java.lang.Thread} to {@link InterruptSource},
+ * Casts current {@link java.lang.Thread} to {@link InterruptSource}
* if applicable, otherwise returns {@code null}.
*/
public static InterruptSource currentThread() {
@@ -74,25 +75,49 @@ public interface InterruptSource {
/**
* {@link java.lang.Thread} specialization implementing {@link InterruptSource}
* to track {@link java.lang.Thread#interrupt()} calls.
+ * @since 2.3.2
*/
public static class Thread extends java.lang.Thread implements InterruptSource {
volatile Throwable interruptSource = null;
volatile int interruptCounter = 0;
final Object sync = new Object();
- public Thread(final String name) {
- super(name);
- }
- public Thread(final Runnable target) {
- super(target);
+ /**
+ * See {@link Thread#Thread(} for details.
+ */
+ public Thread() {
+ super();
}
- public Thread(final Runnable target, final String name) {
- super(target, name);
+ /**
+ * See {@link Thread#Thread(ThreadGroup, Runnable)} for details.
+ * @param tg explicit {@link ThreadGroup}, may be {@code null}
+ * @param target explicit {@link Runnable}, may be {@code null}
+ */
+ public Thread(final ThreadGroup tg, final Runnable target) {
+ super(tg, target);
}
+ /**
+ * See {@link Thread#Thread(ThreadGroup, Runnable, String)} for details.
+ * @param tg explicit {@link ThreadGroup}, may be {@code null}
+ * @param target explicit {@link Runnable}, may be {@code null}
+ * @param name explicit name of thread, must not be {@code null}
+ */
public Thread(final ThreadGroup tg, final Runnable target, final String name) {
super(tg, target, name);
}
+ /**
+ * Depending on whether {@code name} is null, either
+ * {@link #Thread(ThreadGroup, Runnable, String)} or
+ * {@link #Thread(ThreadGroup, Runnable)} is being utilized.
+ * @param tg explicit {@link ThreadGroup}, may be {@code null}
+ * @param target explicit {@link Runnable}, may be {@code null}
+ * @param name explicit name of thread, may be {@code null}
+ */
+ public static Thread create(final ThreadGroup tg, final Runnable target, final String name) {
+ return null != name ? new Thread(tg, target, name) : new Thread(tg, target);
+ }
+
@Override
public final Throwable getInterruptSource(final boolean clear) {
synchronized(sync) {
diff --git a/src/java/com/jogamp/common/util/RunnableTask.java b/src/java/com/jogamp/common/util/RunnableTask.java
index 69d7af2..57809b9 100644
--- a/src/java/com/jogamp/common/util/RunnableTask.java
+++ b/src/java/com/jogamp/common/util/RunnableTask.java
@@ -55,25 +55,27 @@ public class RunnableTask extends TaskBase {
}
/**
- * Invokes <code>runnable</code> on a new thread belonging to the given {@link ThreadGroup}.
+ * Invokes <code>runnable</code> on a new {@link InterruptSource.Thread},
+ * see {@link InterruptSource.Thread#Thread(ThreadGroup, Runnable, String)} for details.
* @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code>
+ * @param threadName the name for the new thread, maybe <code>null</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 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
+ * the runnable <b>must exit</b>, i.e. not loop forever.
* @return the newly created and invoked {@link RunnableTask}
+ * @since 2.3.2
*/
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);
+ final InterruptSource.Thread t = InterruptSource.Thread.create(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);
+ final InterruptSource.Thread t = InterruptSource.Thread.create(tg, rt, threadName);
synchronized(sync) {
t.start();
while( rt.isInQueue() ) {
diff --git a/src/java/com/jogamp/common/util/SourcedInterruptedException.java b/src/java/com/jogamp/common/util/SourcedInterruptedException.java
index 7646652..49dcd86 100644
--- a/src/java/com/jogamp/common/util/SourcedInterruptedException.java
+++ b/src/java/com/jogamp/common/util/SourcedInterruptedException.java
@@ -39,6 +39,7 @@ import com.jogamp.common.ExceptionUtils.CustomStackTrace;
* This exception may be created directly where {@link #getCause()} returns {@code null},
* or by propagating an existing {@link InterruptedException} as returned by {@link #getCause()}.
* </p>
+ * @since 2.3.2
*/
@SuppressWarnings("serial")
public class SourcedInterruptedException extends InterruptedException implements CustomStackTrace {
diff --git a/src/java/com/jogamp/common/util/TaskBase.java b/src/java/com/jogamp/common/util/TaskBase.java
index 518aeba..0fe85e4 100644
--- a/src/java/com/jogamp/common/util/TaskBase.java
+++ b/src/java/com/jogamp/common/util/TaskBase.java
@@ -80,7 +80,10 @@ public abstract class TaskBase implements Runnable {
}
}
- /** Returns the execution thread or {@code null} if not yet {@link #run()}. */
+ /**
+ * Returns the execution thread or {@code null} if not yet {@link #run()}.
+ * @since 2.3.2
+ */
public final Thread getExecutionThread() {
return execThread;
}
@@ -135,7 +138,7 @@ public abstract class TaskBase implements Runnable {
/**
* @return !{@link #isExecuted()} && !{@link #isFlushed()}
*/
- public final boolean isInQueue() { return !isExecuted() && !isFlushed(); }
+ public final boolean isInQueue() { return !isExecuted && !isFlushed; }
/**
* @return True if executed, otherwise false;
diff --git a/src/java/com/jogamp/common/util/cache/TempFileCache.java b/src/java/com/jogamp/common/util/cache/TempFileCache.java
index 24f0237..44c7a11 100644
--- a/src/java/com/jogamp/common/util/cache/TempFileCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempFileCache.java
@@ -35,6 +35,7 @@ import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.InterruptSource;
import jogamp.common.Debug;
@@ -238,7 +239,7 @@ public class TempFileCache {
// Add shutdown hook to cleanup the OutputStream, FileChannel,
// and FileLock for the jlnNNNN.lck and jlnNNNN.lck files.
// We do this so that the locks never get garbage-collected.
- Runtime.getRuntime().addShutdownHook(new Thread() {
+ Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() {
/* @Override */
@Override
public void run() {
@@ -265,7 +266,7 @@ public class TempFileCache {
}
// Start a new Reaper thread to do stuff...
- final Thread reaperThread = new Thread() {
+ final Thread reaperThread = new InterruptSource.Thread() {
/* @Override */
@Override
public void run() {
diff --git a/src/java/jogamp/android/launcher/LauncherTempFileCache.java b/src/java/jogamp/android/launcher/LauncherTempFileCache.java
index 6836dd9..b576ed9 100644
--- a/src/java/jogamp/android/launcher/LauncherTempFileCache.java
+++ b/src/java/jogamp/android/launcher/LauncherTempFileCache.java
@@ -34,6 +34,8 @@ import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
+import com.jogamp.common.util.InterruptSource;
+
import android.content.Context;
public class LauncherTempFileCache {
@@ -223,7 +225,7 @@ public class LauncherTempFileCache {
// Add shutdown hook to cleanup the OutputStream, FileChannel,
// and FileLock for the jlnNNNN.lck and jlnNNNN.lck files.
// We do this so that the locks never get garbage-collected.
- Runtime.getRuntime().addShutdownHook(new Thread() {
+ Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() {
/* @Override */
public void run() {
// NOTE: we don't really expect that this code will ever
@@ -249,7 +251,7 @@ public class LauncherTempFileCache {
}
// Start a new Reaper thread to do stuff...
- final Thread reaperThread = new Thread() {
+ final Thread reaperThread = new InterruptSource.Thread() {
/* @Override */
public void run() {
deleteOldTempDirs();
diff --git a/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java b/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java
index f86dd33..1286924 100644
--- a/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java
+++ b/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java
@@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.AbstractOwnableSynchronizer;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.common.util.locks.RecursiveLock;
/**
@@ -197,7 +198,7 @@ public class RecursiveLockImpl01CompleteFair implements RecursiveLock {
} catch (final InterruptedException e) {
if( !wCur.signaledByUnlock ) {
sync.queue.remove(wCur); // O(n)
- throw e; // propagate interruption not send by unlock
+ throw SourcedInterruptedException.wrap(e); // propagate interruption not send by unlock
} else if( cur != sync.getOwner() ) {
// Issued by unlock, but still locked by other thread
//
diff --git a/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java b/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java
index b1b42c3..8ac73fa 100644
--- a/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java
+++ b/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java
@@ -33,10 +33,16 @@ import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
+
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.common.util.locks.SingletonInstance;
public class SingletonInstanceServerSocket extends SingletonInstance {
+ private static int serverInstanceCount = 0;
private final Server singletonServer;
private final String fullName;
@@ -139,38 +145,58 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
public final boolean start() {
if(alive) return true;
+ final String sname;
+ synchronized (Server.class) {
+ serverInstanceCount++;
+ sname = "SingletonServerSocket"+serverInstanceCount+"-"+fullName;
+ }
synchronized (syncOnStartStop) {
- serverThread = new Thread(this);
+ shallQuit = false;
+ serverThread = InterruptSource.Thread.create(null, this, sname);
serverThread.setDaemon(true); // be a daemon, don't keep the JVM running
serverThread.start();
try {
- syncOnStartStop.wait();
+ while( !alive && !shallQuit ) {
+ syncOnStartStop.wait();
+ }
} catch (final InterruptedException ie) {
- ie.printStackTrace();
+ final InterruptedException ie2 = SourcedInterruptedException.wrap(ie);
+ shutdown(false);
+ throw new InterruptedRuntimeException(ie2);
}
}
final boolean ok = isBound();
if(!ok) {
- shutdown();
+ shutdown(true);
}
return ok;
}
public final boolean shutdown() {
+ return shutdown(true);
+ }
+ private final boolean shutdown(final boolean wait) {
if(!alive) return true;
- synchronized (syncOnStartStop) {
- shallQuit = true;
- connect();
- try {
- syncOnStartStop.wait();
- } catch (final InterruptedException ie) {
- ie.printStackTrace();
+ try {
+ synchronized (syncOnStartStop) {
+ shallQuit = true;
+ connect();
+ if( wait ) {
+ try {
+ while( alive ) {
+ syncOnStartStop.wait();
+ }
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ }
+ }
+ } finally {
+ if(alive) {
+ System.err.println(infoPrefix()+" EEE "+getName()+" - Unable to remove lock: ServerThread still alive ?");
+ kill();
}
- }
- if(alive) {
- System.err.println(infoPrefix()+" EEE "+getName()+" - Unable to remove lock: ServerThread still alive ?");
- kill();
}
return true;
}
@@ -185,7 +211,8 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
System.err.println(infoPrefix()+" XXX "+getName()+" - Kill @ JVM Shutdown");
}
alive = false;
- if(null != serverThread) {
+ shallQuit = false;
+ if(null != serverThread && serverThread.isAlive() ) {
try {
serverThread.stop();
} catch(final Throwable t) { }
@@ -214,47 +241,49 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
@Override
public void run() {
- {
- final Thread currentThread = Thread.currentThread();
- currentThread.setName(currentThread.getName() + " - SISock: "+getName());
- if(DEBUG) {
- System.err.println(currentThread.getName()+" - started");
- }
+ if(DEBUG) {
+ System.err.println(infoPrefix()+" III - Start");
}
- alive = false;
- synchronized (syncOnStartStop) {
- try {
- serverSocket = new ServerSocket(portNumber, 1, localInetAddress);
- serverSocket.setReuseAddress(true); // reuse same port w/ subsequent instance, i.e. overcome TO state when JVM crashed
- alive = true;
- } catch (final IOException e) {
- System.err.println(infoPrefix()+" III - Unable to install ServerSocket: "+e.getMessage());
- shallQuit = true;
- } finally {
- syncOnStartStop.notifyAll();
+ try {
+ synchronized (syncOnStartStop) {
+ try {
+ serverSocket = new ServerSocket(portNumber, 1, localInetAddress);
+ serverSocket.setReuseAddress(true); // reuse same port w/ subsequent instance, i.e. overcome TO state when JVM crashed
+ alive = true;
+ } catch (final IOException e) {
+ System.err.println(infoPrefix()+" III - Unable to install ServerSocket: "+e.getMessage());
+ shallQuit = true;
+ } finally {
+ syncOnStartStop.notifyAll();
+ }
}
- }
- while (!shallQuit) {
- try {
- final Socket clientSocket = serverSocket.accept();
- clientSocket.close();
- } catch (final IOException ioe) {
- System.err.println(infoPrefix()+" EEE - Exception during accept: " + ioe.getMessage());
+ while (!shallQuit) {
+ try {
+ final Socket clientSocket = serverSocket.accept();
+ clientSocket.close();
+ } catch (final IOException ioe) {
+ System.err.println(infoPrefix()+" EEE - Exception during accept: " + ioe.getMessage());
+ }
}
- }
-
- synchronized (syncOnStartStop) {
- try {
+ } catch(final ThreadDeath td) {
+ if( DEBUG ) {
+ ExceptionUtils.dumpThrowable("", td);
+ }
+ } finally {
+ synchronized (syncOnStartStop) {
+ if(DEBUG) {
+ System.err.println(infoPrefix()+" III - Stopping: alive "+alive+", shallQuit "+shallQuit+", hasSocket "+(null!=serverSocket));
+ }
if(null != serverSocket) {
- serverSocket.close();
+ try {
+ serverSocket.close();
+ } catch (final IOException e) {
+ System.err.println(infoPrefix()+" EEE - Exception during close: " + e.getMessage());
+ }
}
- } catch (final IOException e) {
- System.err.println(infoPrefix()+" EEE - Exception during close: " + e.getMessage());
- } finally {
serverSocket = null;
alive = false;
- shallQuit = false;
syncOnStartStop.notifyAll();
}
}
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
index b018a79..a1a9965 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
@@ -35,10 +35,11 @@ import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
+import com.jogamp.junit.util.JunitTracer;
import com.jogamp.junit.util.SingletonJunitCase;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSingletonServerSocket00 {
+public class TestSingletonServerSocket00 extends JunitTracer {
public static final long SINGLE_INSTANCE_LOCK_TO = SingletonJunitCase.SINGLE_INSTANCE_LOCK_TO;
public static final long SINGLE_INSTANCE_LOCK_POLL = 100; // poll every 100ms
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
index b37e600..c637865 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
@@ -35,10 +35,11 @@ import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
+import com.jogamp.junit.util.JunitTracer;
import com.jogamp.junit.util.SingletonJunitCase;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSingletonServerSocket01 {
+public class TestSingletonServerSocket01 extends JunitTracer {
private static volatile SingletonInstance singletonInstance;
@BeforeClass