diff options
author | Sven Gothel <[email protected]> | 2010-10-14 21:30:14 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-10-14 21:30:14 +0200 |
commit | 1c7f8f8dafe0252afbb0e2701687210814b56793 (patch) | |
tree | 99e9830d5b57ab55fc109f30f9196dff6131b810 /src/java/com/jogamp/common/util | |
parent | 52dcea28906b3e61ef44595399e525dd5169c014 (diff) |
Moved locking to: com.jogamp.common.util.locks ; Better abstraction ; Misc changes
Diffstat (limited to 'src/java/com/jogamp/common/util')
-rw-r--r-- | src/java/com/jogamp/common/util/ReflectionUtil.java | 49 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/locks/Lock.java | 77 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/locks/LockExt.java | 50 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/locks/RecursiveLock.java (renamed from src/java/com/jogamp/common/util/RecursiveToolkitLock.java) | 76 |
4 files changed, 209 insertions, 43 deletions
diff --git a/src/java/com/jogamp/common/util/ReflectionUtil.java b/src/java/com/jogamp/common/util/ReflectionUtil.java index a04ec73..bf4624f 100644 --- a/src/java/com/jogamp/common/util/ReflectionUtil.java +++ b/src/java/com/jogamp/common/util/ReflectionUtil.java @@ -42,7 +42,9 @@ import com.jogamp.common.impl.Debug; public final class ReflectionUtil { - public static final boolean DEBUG = Debug.debug("ReflectionUtil"); + public static final boolean DEBUG = Debug.debug("ReflectionUtil"); + + private static final Class[] zeroTypes = new Class[0]; /** * Returns true only if the class could be loaded. @@ -87,12 +89,14 @@ public final class ReflectionUtil { static final String asString(Class[] argTypes) { StringBuffer args = new StringBuffer(); boolean coma = false; - for (int i = 0; i < argTypes.length; i++) { - if(coma) { - args.append(", "); + if(null != argTypes) { + for (int i = 0; i < argTypes.length; i++) { + if(coma) { + args.append(", "); + } + args.append(argTypes[i].getName()); + coma = true; } - args.append(argTypes[i].getName()); - coma = true; } return args.toString(); } @@ -103,6 +107,9 @@ public final class ReflectionUtil { public static final Constructor getConstructor(Class clazz, Class[] cstrArgTypes) throws JogampRuntimeException { try { + if(null == cstrArgTypes) { + cstrArgTypes = zeroTypes; + } return clazz.getDeclaredConstructor(cstrArgTypes); } catch (NoSuchMethodException ex) { throw new JogampRuntimeException("Constructor: '" + clazz + "(" + asString(cstrArgTypes) + ")' not found", ex); @@ -111,7 +118,7 @@ public final class ReflectionUtil { public static final Constructor getConstructor(String clazzName, ClassLoader cl) throws JogampRuntimeException { - return getConstructor(clazzName, new Class[0], cl); + return getConstructor(clazzName, null, cl); } /** @@ -140,9 +147,12 @@ public final class ReflectionUtil { public static final Object createInstance(Class clazz, Object[] cstrArgs) throws JogampRuntimeException, RuntimeException { - Class[] cstrArgTypes = new Class[cstrArgs.length]; - for(int i=0; i<cstrArgs.length; i++) { - cstrArgTypes[i] = cstrArgs[i].getClass(); + Class[] cstrArgTypes = null; + if(null!=cstrArgs) { + cstrArgTypes = new Class[cstrArgs.length]; + for(int i=0; i<cstrArgs.length; i++) { + cstrArgTypes[i] = cstrArgs[i].getClass(); + } } return createInstance(clazz, cstrArgTypes, cstrArgs); } @@ -160,9 +170,12 @@ public final class ReflectionUtil { public static final Object createInstance(String clazzName, Object[] cstrArgs, ClassLoader cl) throws JogampRuntimeException, RuntimeException { - Class[] cstrArgTypes = new Class[cstrArgs.length]; - for(int i=0; i<cstrArgs.length; i++) { - cstrArgTypes[i] = cstrArgs[i].getClass(); + Class[] cstrArgTypes = null; + if(null!=cstrArgs) { + cstrArgTypes = new Class[cstrArgs.length]; + for(int i=0; i<cstrArgs.length; i++) { + cstrArgTypes[i] = cstrArgs[i].getClass(); + } } return createInstance(clazzName, cstrArgTypes, cstrArgs, cl); } @@ -170,7 +183,7 @@ public final class ReflectionUtil { public static final Object createInstance(String clazzName, ClassLoader cl) throws JogampRuntimeException, RuntimeException { - return createInstance(clazzName, new Class[0], null, cl); + return createInstance(clazzName, null, null, cl); } public static final boolean instanceOf(Object obj, String clazzName) { @@ -239,8 +252,12 @@ public final class ReflectionUtil { } /** - * @throws JogampRuntimeException if the call fails - * @throws RuntimeException if the call fails + * @param instance may be null in case of a static method + * @param method the method to be called + * @param args the method arguments + * @return the methods result, maybe null if void + * @throws JogampRuntimeException if call fails + * @throws RuntimeException if call fails */ public static final Object callMethod(Object instance, Method method, Object[] args) throws JogampRuntimeException, RuntimeException diff --git a/src/java/com/jogamp/common/util/locks/Lock.java b/src/java/com/jogamp/common/util/locks/Lock.java new file mode 100644 index 0000000..7065ff8 --- /dev/null +++ b/src/java/com/jogamp/common/util/locks/Lock.java @@ -0,0 +1,77 @@ +/** + * 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.locks; + +import com.jogamp.common.impl.Debug; +import java.security.AccessController; + +/** + * Specifying a thread blocking lock implementation + */ +public interface Lock { + + /** Enable via the property <code>jogamp.debug.Lock</code> */ + public static final boolean DEBUG = Debug.debug("Lock"); + + /** Defines the default {@link #TIMEOUT} value */ + public static final long DEFAULT_TIMEOUT = 5000; // 5s default timeout + + /** + * Defines the <code>TIMEOUT</code> for {@link #lock()} in ms, + * and defaults to {@link #DEFAULT_TIMEOUT}.<br> + * It can be overriden via the system property <code>jogamp.common.utils.locks.Lock.timeout</code>. + */ + public static final long TIMEOUT = Debug.getLongProperty("jogamp.common.utils.locks.Lock.timeout", true, AccessController.getContext(), DEFAULT_TIMEOUT); + + /** + * Blocking until the lock is acquired by this Thread or {@link #TIMEOUT} is reached. + * + * @throws RuntimeException in case of {@link #TIMEOUT} + */ + void lock() throws RuntimeException; + + /** + * Blocking until the lock is acquired by this Thread or <code>maxwait</code> in ms is reached. + * + * @param maxwait Maximum time in ms to wait to acquire the lock. If this value is zero, + * the call returns immediately either without being able + * to acquire the lock, or with acquiring the lock directly while ignoring any scheduling order. + * @return true if the lock has been acquired within <code>maxwait</code>, otherwise false + * + * @throws RuntimeException in case of {@link #TIMEOUT} + */ + boolean tryLock(long maxwait) throws RuntimeException; + + /** + * Unblocking. + * + * @throws RuntimeException in case the lock is not acquired by this thread. + */ + void unlock() throws RuntimeException; +} diff --git a/src/java/com/jogamp/common/util/locks/LockExt.java b/src/java/com/jogamp/common/util/locks/LockExt.java new file mode 100644 index 0000000..42a01c6 --- /dev/null +++ b/src/java/com/jogamp/common/util/locks/LockExt.java @@ -0,0 +1,50 @@ +/** + * 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.locks; + +/** + * Extending the {@link Lock} features with convenient functionality. + */ +public interface LockExt extends Lock { + + /** + * @return the Thread owning this lock if locked, otherwise null + */ + Thread getOwner(); + + boolean isLocked(); + + boolean isLockedByOtherThread(); + + boolean isOwner(); + + boolean isOwner(Thread thread); + + void validateLocked(); +} diff --git a/src/java/com/jogamp/common/util/RecursiveToolkitLock.java b/src/java/com/jogamp/common/util/locks/RecursiveLock.java index e02ff94..010467b 100644 --- a/src/java/com/jogamp/common/util/RecursiveToolkitLock.java +++ b/src/java/com/jogamp/common/util/locks/RecursiveLock.java @@ -26,23 +26,25 @@ * or implied, of JogAmp Community. */ -package com.jogamp.common.util; +package com.jogamp.common.util.locks; import com.jogamp.common.impl.Debug; +import java.security.AccessController; import java.util.LinkedList; /** * Reentrance locking toolkit, impl a complete fair FIFO scheduler */ -public class RecursiveToolkitLock { +public class RecursiveLock implements LockExt { + static class SyncData { // owner of the lock Thread owner = null; // lock recursion int recursionCount = 0; - // stack trace of the lock - Exception lockedStack = null; + // stack trace of the lock, only used if DEBUG + Throwable lockedStack = null; // waiting thread queue LinkedList threadQueue = new LinkedList(); // flag signaling unlock has woken up a waiting thread @@ -50,20 +52,17 @@ public class RecursiveToolkitLock { } private SyncData sdata = new SyncData(); // synchronized (flow/mem) mutable access - private long timeout; - private static final long defaultTimeout = 5000; // default maximum wait 5s - // private static final long defaultTimeout = 300000; // default maximum wait 300s / 5min - private static final boolean TRACE_LOCK = Debug.debug("TraceLock"); - - public RecursiveToolkitLock() { - this.timeout = defaultTimeout; - } + private static final boolean TRACE_LOCK = Debug.isPropertyDefined("jogamp.debug.Lock.TraceLock", true, AccessController.getContext()); - public RecursiveToolkitLock(long timeout) { - this.timeout = timeout; + public RecursiveLock() { } - public final Exception getLockedStack() { + /** + * Returns the Throwable instance generated when this lock was taken the 1st time + * and if {@link com.jogamp.common.util.locks.Lock#DEBUG} is turned on, otherwise it returns always <code>null</code>. + * @see com.jogamp.common.util.locks.Lock#DEBUG + */ + public final Throwable getLockedStack() { synchronized(sdata) { return sdata.lockedStack; } @@ -109,32 +108,55 @@ public class RecursiveToolkitLock { throw new RuntimeException(Thread.currentThread()+": Not locked"); } if ( Thread.currentThread() != sdata.owner ) { - getLockedStack().printStackTrace(); + if(null!=sdata.lockedStack) { + sdata.lockedStack.printStackTrace(); + } throw new RuntimeException(Thread.currentThread()+": Not owner, owner is "+sdata.owner); } } } - /** Recursive and blocking lockSurface() implementation */ public final void lock() { synchronized(sdata) { + if(!tryLock(TIMEOUT)) { + if(null!=sdata.lockedStack) { + sdata.lockedStack.printStackTrace(); + } + throw new RuntimeException("Waited "+TIMEOUT+"ms for: "+sdata.owner+" - "+Thread.currentThread()+", with recursionCount "+sdata.recursionCount+", lock: "+this+", qsz "+sdata.threadQueue.size()); + } + } + } + + public boolean tryLock(long maxwait) { + synchronized(sdata) { Thread cur = Thread.currentThread(); + if(TRACE_LOCK) { + Throwable tt = new Throwable("LOCK 0 ["+this+"], recursions "+sdata.recursionCount+", cur "+cur+", owner "+sdata.owner); + tt.printStackTrace(); + } if (sdata.owner == cur) { ++sdata.recursionCount; if(TRACE_LOCK) { System.err.println("+++ LOCK 2 ["+this+"], recursions "+sdata.recursionCount+", "+cur); } - return; + return true; } - if (sdata.owner != null || sdata.signaled || sdata.threadQueue.size() > 0) { - // enqueue due to locked resource or already waiting or signaled threads (be fair) + if ( sdata.owner != null || + 0 < maxwait && ( sdata.signaled || sdata.threadQueue.size() > 0 ) ) { + + if ( 0 >= maxwait ) { + // implies 'sdata.owner != null': locked by other thread + // no waiting requested, bail out right away + return false; + } + boolean timedOut = false; do { sdata.threadQueue.addFirst(cur); // should only happen once try { - sdata.wait(timeout); - timedOut = sdata.threadQueue.remove(cur); // timeout if not already removed by unlock + sdata.wait(maxwait); + timedOut = sdata.threadQueue.remove(cur); // TIMEOUT if not already removed by unlock } catch (InterruptedException e) { if(!sdata.signaled) { // theoretically we could stay in the loop, @@ -151,8 +173,7 @@ public class RecursiveToolkitLock { sdata.signaled = false; if(timedOut || null != sdata.owner) { - sdata.lockedStack.printStackTrace(); - throw new RuntimeException("Waited "+timeout+"ms for: "+sdata.owner+" - "+cur+", with recursionCount "+sdata.recursionCount+", lock: "+this+", qsz "+sdata.threadQueue.size()); + return false; } if(TRACE_LOCK) { @@ -163,17 +184,18 @@ public class RecursiveToolkitLock { } sdata.owner = cur; - sdata.lockedStack = new Exception("Previously locked by "+sdata.owner+", lock: "+this); + if(DEBUG) { + sdata.lockedStack = new Throwable("Previously locked by "+sdata.owner+", lock: "+this); + } + return true; } } - /** Recursive and unblocking unlockSurface() implementation */ public final void unlock() { unlock(null); } - /** Recursive and unblocking unlockSurface() implementation */ public final void unlock(Runnable taskAfterUnlockBeforeNotify) { synchronized(sdata) { validateLocked(); |