libproxool-java-0.9.1.orig/ 0000755 0001750 0001750 00000000000 11053761073 015531 5 ustar twerner twerner libproxool-java-0.9.1.orig/doc/ 0000755 0001750 0001750 00000000000 11054125603 016270 5 ustar twerner twerner libproxool-java-0.9.1.orig/lib/ 0000755 0001750 0001750 00000000000 11054125603 016271 5 ustar twerner twerner libproxool-java-0.9.1.orig/src/ 0000755 0001750 0001750 00000000000 11053761073 016320 5 ustar twerner twerner libproxool-java-0.9.1.orig/src/java/ 0000755 0001750 0001750 00000000000 11054125603 017233 5 ustar twerner twerner libproxool-java-0.9.1.orig/src/java/org/ 0000755 0001750 0001750 00000000000 11053761073 020030 5 ustar twerner twerner libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/ 0000755 0001750 0001750 00000000000 11053761073 023007 5 ustar twerner twerner libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/ 0000755 0001750 0001750 00000000000 11054125603 025163 5 ustar twerner twerner libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/BoundedChannel.java 0000644 0001750 0001750 00000002143 10730503124 030675 0 ustar twerner twerner /*
File: BoundedChannel.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package org.logicalcobwebs.concurrent;
/**
* A channel that is known to have a capacity, signifying
* that put
operations may block when the
* capacity is reached. Various implementations may have
* intrinsically hard-wired capacities, capacities that are fixed upon
* construction, or dynamically adjustable capacities.
* @see DefaultChannelCapacity
*
[ Introduction to this package. ]
**/ public interface BoundedChannel extends Channel { /** * Return the maximum number of elements that can be held. * @return the capacity of this channel. **/ public int capacity(); } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/Callable.java 0000644 0001750 0001750 00000002237 10730503124 027527 0 ustar twerner twerner /* File: Callable.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 30Jun1998 dl Create public version 5Jan1999 dl Change Exception to Throwable in call signature 27Jan1999 dl Undo last change */ package org.logicalcobwebs.concurrent; /** * Interface for runnable actions that bear results and/or throw Exceptions. * This interface is designed to provide a common protocol for * result-bearing actions that can be run independently in threads, * in which case * they are ordinarily used as the bases of Runnables that set * FutureResults *
*
[ Introduction to this package. ] * @see FutureResult **/ public interface Callable { /** Perform some action that returns a result or throws an exception **/ Object call() throws Exception; } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/Channel.java 0000644 0001750 0001750 00000025534 10730503124 027405 0 ustar twerner twerner /* File: Channel.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version 25aug1998 dl added peek */ package org.logicalcobwebs.concurrent; /** * Main interface for buffers, queues, pipes, conduits, etc. *
* A Channel represents anything that you can put items * into and take them out of. As with the Sync * interface, both * blocking (put(x), take), * and timeouts (offer(x, msecs), poll(msecs)) policies * are provided. Using a * zero timeout for offer and poll results in a pure balking policy. *
* To aid in efforts to use Channels in a more typesafe manner, * this interface extends Puttable and Takable. You can restrict * arguments of instance variables to this type as a way of * guaranteeing that producers never try to take, or consumers put. * for example: *
* class Producer implements Runnable { * final Puttable chan; * Producer(Puttable channel) { chan = channel; } * public void run() { * try { * for(;;) { chan.put(produce()); } * } * catch (InterruptedException ex) {} * } * Object produce() { ... } * } * * * class Consumer implements Runnable { * final Takable chan; * Consumer(Takable channel) { chan = channel; } * public void run() { * try { * for(;;) { consume(chan.take()); } * } * catch (InterruptedException ex) {} * } * void consume(Object x) { ... } * } * * class Setup { * void main() { * Channel chan = new SomeChannelImplementation(); * Producer p = new Producer(chan); * Consumer c = new Consumer(chan); * new Thread(p).start(); * new Thread(c).start(); * } * } **
* A given channel implementation might or might not have bounded * capacity or other insertion constraints, so in general, you cannot tell if * a given put will block. However, * Channels that are designed to * have an element capacity (and so always block when full) * should implement the * BoundedChannel * subinterface. *
* Channels may hold any kind of item. However, * insertion of null is not in general supported. Implementations * may (all currently do) throw IllegalArgumentExceptions upon attempts to * insert null. *
* By design, the Channel interface does not support any methods to determine * the current number of elements being held in the channel. * This decision reflects the fact that in * concurrent programming, such methods are so rarely useful * that including them invites misuse; at best they could * provide a snapshot of current * state, that could change immediately after being reported. * It is better practice to instead use poll and offer to try * to take and put elements without blocking. For example, * to empty out the current contents of a channel, you could write: *
* try { * for (;;) { * Object item = channel.poll(0); * if (item != null) * process(item); * else * break; * } * } * catch(InterruptedException ex) { ... } **
* However, it is possible to determine whether an item
* exists in a Channel via peek
, which returns
* but does NOT remove the next item that can be taken (or null
* if there is no such item). The peek operation has a limited
* range of applicability, and must be used with care. Unless it
* is known that a given thread is the only possible consumer
* of a channel, and that no time-out-based offer
operations
* are ever invoked, there is no guarantee that the item returned
* by peek will be available for a subsequent take.
*
* When appropriate, you can define an isEmpty method to
* return whether peek
returns null.
*
* Also, as a compromise, even though it does not appear in interface,
* implementation classes that can readily compute the number
* of elements support a size()
method. This allows careful
* use, for example in queue length monitors, appropriate to the
* particular implementation constraints and properties.
*
* All channels allow multiple producers and/or consumers. * They do not support any kind of close method * to shut down operation or indicate completion of particular * producer or consumer threads. * If you need to signal completion, one way to do it is to * create a class such as *
* class EndOfStream { * // Application-dependent field/methods * } ** And to have producers put an instance of this class into * the channel when they are done. The consumer side can then * check this via *
* Object x = aChannel.take(); * if (x instanceof EndOfStream) * // special actions; perhaps terminate * else * // process normally **
* In time-out based methods (poll(msecs) and offer(x, msecs), * time bounds are interpreted in * a coarse-grained, best-effort fashion. Since there is no * way in Java to escape out of a wait for a synchronized * method/block, time bounds can sometimes be exceeded when * there is a lot contention for the channel. Additionally, * some Channel semantics entail a ``point of * no return'' where, once some parts of the operation have completed, * others must follow, regardless of time bound. *
* Interruptions are in general handled as early as possible * in all methods. Normally, InterruptionExceptions are thrown * in put/take and offer(msec)/poll(msec) if interruption * is detected upon entry to the method, as well as in any * later context surrounding waits. *
* If a put returns normally, an offer * returns true, or a put or poll returns non-null, the operation * completed successfully. * In all other cases, the operation fails cleanly -- the * element is not put or taken. *
* As with Sync classes, spinloops are not directly supported, * are not particularly recommended for routine use, but are not hard * to construct. For example, here is an exponential backoff version: *
* Object backOffTake(Channel q) throws InterruptedException { * long waitTime = 0; * for (;;) { * Object x = q.poll(0); * if (x != null) * return x; * else { * Thread.sleep(waitTime); * waitTime = 3 * waitTime / 2 + 1; * } * } **
* Sample Usage. Here is a producer/consumer design * where the channel is used to hold Runnable commands representing * background tasks. *
* class Service { * private final Channel channel = ... some Channel implementation; * * private void backgroundTask(int taskParam) { ... } * * public void action(final int arg) { * Runnable command = * new Runnable() { * public void run() { backgroundTask(arg); } * }; * try { channel.put(command) } * catch (InterruptedException ex) { * Thread.currentThread().interrupt(); // ignore but propagate * } * } * * public Service() { * Runnable backgroundLoop = * new Runnable() { * public void run() { * for (;;) { * try { * Runnable task = (Runnable)(channel.take()); * task.run(); * } * catch (InterruptedException ex) { return; } * } * } * }; * new Thread(backgroundLoop).start(); * } * } * **
[ Introduction to this package. ] * @see Sync * @see BoundedChannel **/ public interface Channel extends Puttable, Takable { /** * Place item in the channel, possibly waiting indefinitely until * it can be accepted. Channels implementing the BoundedChannel * subinterface are generally guaranteed to block on puts upon * reaching capacity, but other implementations may or may not block. * @param item the element to be inserted. Should be non-null. * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case the element is guaranteed not * to be inserted. Otherwise, on normal return, the element is guaranteed * to have been inserted. **/ public void put(Object item) throws InterruptedException; /** * Place item in channel only if it can be accepted within * msecs milliseconds. The time bound is interpreted in * a coarse-grained, best-effort fashion. * @param item the element to be inserted. Should be non-null. * @param msecs the number of milliseconds to wait. If less than * or equal to zero, the method does not perform any timed waits, * but might still require * access to a synchronization lock, which can impose unbounded * delay if there is a lot of contention for the channel. * @return true if accepted, else false * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case the element is guaranteed not * to be inserted (i.e., is equivalent to a false return). **/ public boolean offer(Object item, long msecs) throws InterruptedException; /** * Return and remove an item from channel, * possibly waiting indefinitely until * such an item exists. * @return some item from the channel. Different implementations * may guarantee various properties (such as FIFO) about that item * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case state of the channel is unchanged. * **/ public Object take() throws InterruptedException; /** * Return and remove an item from channel only if one is available within * msecs milliseconds. The time bound is interpreted in a coarse * grained, best-effort fashion. * @param msecs the number of milliseconds to wait. If less than * or equal to zero, the operation does not perform any timed waits, * but might still require * access to a synchronization lock, which can impose unbounded * delay if there is a lot of contention for the channel. * @return some item, or null if the channel is empty. * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case state of the channel is unchanged * (i.e., equivalent to a null return). **/ public Object poll(long msecs) throws InterruptedException; /** * Return, but do not remove object at head of Channel, * or null if it is empty. **/ public Object peek(); } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/DefaultChannelCapacity.java 0000644 0001750 0001750 00000003433 10730503124 032362 0 ustar twerner twerner /* File: DefaultChannelCapacity.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * A utility class to set the default capacity of * BoundedChannel * implementations that otherwise require a capacity argument * @see BoundedChannel * [ Introduction to this package. ]
**/
public class DefaultChannelCapacity {
/** The initial value of the default capacity is 1024 **/
public static final int INITIAL_DEFAULT_CAPACITY = 1024;
/** the current default capacity **/
private static final SynchronizedInt defaultCapacity_ =
new SynchronizedInt(INITIAL_DEFAULT_CAPACITY);
/**
* Set the default capacity used in
* default (no-argument) constructor for BoundedChannels
* that otherwise require a capacity argument.
* @exception IllegalArgumentException if capacity less or equal to zero
*/
public static void set(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
defaultCapacity_.set(capacity);
}
/**
* Get the default capacity used in
* default (no-argument) constructor for BoundedChannels
* that otherwise require a capacity argument.
* Initial value is INITIAL_DEFAULT_CAPACITY
* @see #INITIAL_DEFAULT_CAPACITY
*/
public static int get() {
return defaultCapacity_.get();
}
}
libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/Executor.java 0000644 0001750 0001750 00000005121 10730503124 027621 0 ustar twerner twerner /*
File: Executor.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
*/
package org.logicalcobwebs.concurrent;
/**
* Interface for objects that execute Runnables,
* as well as various objects that can be wrapped
* as Runnables.
* The main reason to use Executor throughout a program or
* subsystem is to provide flexibility: You can easily
* change from using thread-per-task to using pools or
* queuing, without needing to change most of your code that
* generates tasks.
*
* The general intent is that execution be asynchronous,
* or at least independent of the caller. For example,
* one of the simplest implementations of execute
* (as performed in ThreadedExecutor)
* is new Thread(command).start();
.
* However, this interface allows implementations that instead
* employ queueing or pooling, or perform additional
* bookkeeping.
*
* *
[ Introduction to this package. ] **/ public interface Executor { /** * Execute the given command. This method is guaranteed * only to arrange for execution, that may actually * occur sometime later; for example in a new * thread. However, in fully generic use, callers * should be prepared for execution to occur in * any fashion at all, including immediate direct * execution. *
* The method is defined not to throw * any checked exceptions during execution of the command. Generally, * any problems encountered will be asynchronous and * so must be dealt with via callbacks or error handler * objects. If necessary, any context-dependent * catastrophic errors encountered during * actions that arrange for execution could be accompanied * by throwing context-dependent unchecked exceptions. *
* However, the method does throw InterruptedException: * It will fail to arrange for execution * if the current thread is currently interrupted. * Further, the general contract of the method is to avoid, * suppress, or abort execution if interruption is detected * in any controllable context surrounding execution. **/ public void execute(Runnable command) throws InterruptedException; } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/FJTask.java 0000644 0001750 0001750 00000046133 10730503124 027155 0 ustar twerner twerner /* File: Task.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 7Jan1999 dl first release 14jan1999 dl simplify start() semantics; improve documentation 18Jan1999 dl Eliminate useless time-based waits. 7Mar1999 dl Add reset method, add array-based composite operations 27Apr1999 dl Rename */ package org.logicalcobwebs.concurrent; /** * Abstract base class for Fork/Join Tasks. * *
* FJTasks are lightweight, stripped-down analogs of Threads. * Many FJTasks share the same pool of Java threads. This is * supported by the FJTaskRunnerGroup and FJTaskRunner classes, that * mainly contain * methods called only internally by FJTasks. * FJTasks support versions of the most common methods found in class Thread, * including start(), yield() and join(). However, they * don't support priorities, ThreadGroups or other bookkeeping * or control methods of class Thread. *
* FJTasks should normally be defined by subclassing and adding a run() method.
* Alternatively, static inner class Wrap(Runnable r)
* can be used to
* wrap an existing Runnable object in a FJTask.
*
* FJTaskRunnerGroup.execute(FJTask)
can be used to
* initiate a FJTask from a non-FJTask thread.
* And FJTaskRunnerGroup.invoke(FJTask)
can be used to initiate
* a FJTask and then wait for it to complete before returning.
* These are the only entry-points from normal threads to FJTasks.
* Most FJTask methods themselves may only be called from within running FJTasks.
* They throw ClassCastExceptions if they are not,
* reflecting the fact that these methods
* can only be executed using FJTaskRunner threads, not generic
* java.lang.Threads.
*
* There are three different ways to run a FJTask, * with different scheduling semantics: *
* The main economies of FJTasks stem from the fact that * FJTasks do not support blocking operations of any kind. * FJTasks should just run to completion without * issuing waits or performing blocking IO. * There are several styles for creating the run methods that * execute as tasks, including * event-style methods, and pure computational methods. * Generally, the best kinds of FJTasks are those that in turn * generate other FJTasks. *
* There is nothing actually * preventing you from blocking within a FJTask, and very short waits/blocks are * completely well behaved. But FJTasks are not designed * to support arbitrary synchronization * since there is no way to suspend and resume individual tasks * once they have begun executing. FJTasks should also be finite * in duration -- they should not contain infinite loops. * FJTasks that might need to perform a blocking * action, or hold locks for extended periods, or * loop forever can instead create normal * java Thread objects that will do so. FJTasks are just not * designed to support these things. * FJTasks may however yield() control to allow their FJTaskRunner threads * to run other tasks, * and may wait for other dependent tasks via join(). These * are the only coordination mechanisms supported by FJTasks. *
* FJTasks, and the FJTaskRunners that execute them are not * intrinsically robust with respect to exceptions. * A FJTask that aborts via an exception does not automatically * have its completion flag (isDone) set. * As with ordinary Threads, an uncaught exception will normally cause * its FJTaskRunner thread to die, which in turn may sometimes * cause other computations being performed to hang or abort. * You can of course * do better by trapping exceptions inside the run methods of FJTasks. *
* The overhead differences between FJTasks and Threads are substantial, * especially when using fork() or coInvoke(). * FJTasks can be two or three orders of magnitude faster than Threads, * at least when run on JVMs with high-performance garbage collection * (every FJTask quickly becomes garbage) and good native thread support. *
* Given these overhead savings, you might be tempted to use FJTasks for * everything you would use a normal Thread to do. Don't. Java Threads * remain better for general purpose thread-based programming. Remember * that FJTasks cannot be used for designs involving arbitrary blocking * synchronization or I/O. Extending FJTasks to support such capabilities * would amount to re-inventing the Thread class, and would make them * less optimal in the contexts that they were designed for. *
[ Introduction to this package. ] *
* @see FJTaskRunner * @see FJTaskRunnerGroup **/ public abstract class FJTask implements Runnable { /** * The only status information associated with FJTasks is whether * the they are considered to have completed. * It is set true automatically within * FJTaskRunner methods upon completion * of the run method, or manually via cancel. **/ private volatile boolean done; // = false; /** * Return the FJTaskRunner thread running the current FJTask. * Most FJTask methods are just relays to their current * FJTaskRunners, that perform the indicated actions. * @exception ClassCastException if caller thread is not a * running FJTask. **/ public static FJTaskRunner getFJTaskRunner() { return (FJTaskRunner) (Thread.currentThread()); } /** * Return the FJTaskRunnerGroup of the thread running the current FJTask. * @exception ClassCastException if caller thread is not a * running FJTask. **/ public static FJTaskRunnerGroup getFJTaskRunnerGroup() { return getFJTaskRunner().getGroup(); } /** * Return true if current task has terminated or been cancelled. * The method is a simple analog of the Thread.isAlive() * method. However, it reports true only when the task has terminated * or has been cancelled. It does not distinguish these two cases. * And there is no way to determine whether a FJTask has been started * or is currently executing. **/ public final boolean isDone() { return done; } /** * Indicate termination. Intended only to be called by FJTaskRunner. * FJTasks themselves should use (non-final) method * cancel() to suppress execution. **/ protected final void setDone() { done = true; } /** * Set the termination status of this task. This simple-minded * analog of Thread.interrupt * causes the task not to execute if it has not already been started. * Cancelling a running FJTask * has no effect unless the run method itself uses isDone() * to probe cancellation and take appropriate action. * Individual run() methods may sense status and * act accordingly, normally by returning early. **/ public void cancel() { setDone(); } /** * Clear the termination status of this task. * This method is intended to be used * only as a means to allow task objects to be recycled. It should * be called only when you are sure that the previous * execution of this task has terminated and, if applicable, has * been joined by all other waiting tasks. Usage in any other * context is a very bad idea. **/ public void reset() { done = false; } /** * Execute this task. This method merely places the task in a * group-wide scheduling queue. * It will be run * the next time any TaskRunner thread is otherwise idle. * This scheduling maintains FIFO ordering of started tasks * with respect to * the group of worker threads. * @exception ClassCastException if caller thread is not * running in a FJTaskRunner thread. **/ public void start() { getFJTaskRunnerGroup().executeTask(this); } /** * Arrange for execution of a strictly dependent task. * The task that will be executed in * procedure-call-like LIFO order if executed by the * same worker thread, but is FIFO with respect to other tasks * forked by this thread when taken by other worker threads. * That is, earlier-forked * tasks are preferred to later-forked tasks by other idle workers. *
* Fork() is noticeably * faster than start(). However, it may only * be used for strictly dependent tasks -- generally, those that * could logically be issued as straight method calls without * changing the logic of the program. * The method is optimized for use in parallel fork/join designs * in which the thread that issues one or more forks * cannot continue until at least some of the forked * threads terminate and are joined. * @exception ClassCastException if caller thread is not * running in a FJTaskRunner thread. **/ public void fork() { getFJTaskRunner().push(this); } /** * Allow the current underlying FJTaskRunner thread to process other tasks. *
* Spinloops based on yield() are well behaved so long * as the event or condition being waited for is produced via another * FJTask. Additionally, you must never hold a lock * while performing a yield or join. (This is because * multiple FJTasks can be run by the same Thread during * a yield. Since java locks are held per-thread, the lock would not * maintain the conceptual exclusion you have in mind.) *
* Otherwise, spinloops using
* yield are the main construction of choice when a task must wait
* for a condition that it is sure will eventually occur because it
* is being produced by some other FJTask. The most common
* such condition is built-in: join() repeatedly yields until a task
* has terminated after producing some needed results. You can also
* use yield to wait for callbacks from other FJTasks, to wait for
* status flags to be set, and so on. However, in all these cases,
* you should be confident that the condition being waited for will
* occur, essentially always because it is produced by
* a FJTask generated by the current task, or one of its subtasks.
*
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public static void yield() {
getFJTaskRunner().taskYield();
}
/**
* Yield until this task isDone.
* Equivalent to while(!isDone()) yield();
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public void join() {
getFJTaskRunner().taskJoin(this);
}
/**
* Immediately execute task t by calling its run method. Has no
* effect if t has already been run or has been cancelled.
* It is equivalent to calling t.run except that it
* deals with completion status, so should always be used
* instead of directly calling run.
* The method can be useful
* when a computation has been packaged as a FJTask, but you just need to
* directly execute its body from within some other task.
**/
public static void invoke(FJTask t) {
if (!t.isDone()) {
t.run();
t.setDone();
}
}
/**
* Fork both tasks and then wait for their completion. It behaves as:
*
* task1.fork(); task2.fork(); task2.join(); task1.join(); ** As a simple classic example, here is * a class that computes the Fibonacci function: *
* public class Fib extends FJTask { * * // Computes fibonacci(n) = fibonacci(n-1) + fibonacci(n-2); for n> 1 * // fibonacci(0) = 0; * // fibonacci(1) = 1. * * // Value to compute fibonacci function for. * // It is replaced with the answer when computed. * private volatile int number; * * public Fib(int n) { number = n; } * * public int getAnswer() { * if (!isDone()) throw new Error("Not yet computed"); * return number; * } * * public void run() { * int n = number; * if (n > 1) { * Fib f1 = new Fib(n - 1); * Fib f2 = new Fib(n - 2); * * coInvoke(f1, f2); // run these in parallel * * // we know f1 and f2 are computed, so just directly access numbers * number = f1.number + f2.number; * } * } * * public static void main(String[] args) { // sample driver * try { * int groupSize = 2; // 2 worker threads * int num = 35; // compute fib(35) * FJTaskRunnerGroup group = new FJTaskRunnerGroup(groupSize); * Fib f = new Fib(num); * group.invoke(f); * int result = f.getAnswer(); * System.out.println(" Answer: " + result); * } * catch (InterruptedException ex) { * System.out.println("Interrupted"); * } * } * } ** * @exception ClassCastException if caller thread is not * running in a FJTaskRunner thread. **/ public static void coInvoke(FJTask task1, FJTask task2) { getFJTaskRunner().coInvoke(task1, task2); } /** * Fork all tasks in array, and await their completion. * Behaviorally equivalent to: *
* for (int i = 0; i < tasks.length; ++i) tasks[i].fork(); * for (int i = 0; i < tasks.length; ++i) tasks[i].join(); ***/ public static void coInvoke(FJTask[] tasks) { getFJTaskRunner().coInvoke(tasks); } /** * A FJTask that holds a Runnable r, and calls r.run when executed. * The class is a simple utilty to allow arbitrary Runnables * to be used as FJTasks. **/ public static class Wrap extends FJTask { protected final Runnable runnable; public Wrap(Runnable r) { runnable = r; } public void run() { runnable.run(); } } /** * A
new Seq
, when executed,
* invokes each task provided in the constructor, in order.
* The class is a simple utility
* that makes it easier to create composite FJTasks.
**/
public static class Seq extends FJTask {
protected final FJTask[] tasks;
/**
* Construct a Seq that, when executed, will process each of the
* tasks in the tasks array in order
**/
public Seq(FJTask[] tasks) {
this.tasks = tasks;
}
/**
* Two-task constructor, for compatibility with previous release.
**/
public Seq(FJTask task1, FJTask task2) {
this.tasks = new FJTask[]{task1, task2};
}
public void run() {
for (int i = 0; i < tasks.length; ++i) FJTask.invoke(tasks[i]);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke the tasks in the tasks array in array order
**/
public static FJTask seq(FJTask[] tasks) {
return new Seq(tasks);
}
/**
* A new Par
, when executed,
* runs the tasks provided in the constructor in parallel using
* coInvoke(tasks).
* The class is a simple utility
* that makes it easier to create composite FJTasks.
**/
public static class Par extends FJTask {
protected final FJTask[] tasks;
/**
* Construct a Seq that, when executed, will process each of the
* tasks in the tasks array in parallel
**/
public Par(FJTask[] tasks) {
this.tasks = tasks;
}
/**
* Two-task constructor, for compatibility with previous release.
**/
public Par(FJTask task1, FJTask task2) {
this.tasks = new FJTask[]{task1, task2};
}
public void run() {
FJTask.coInvoke(tasks);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke the tasks in the tasks array in parallel using coInvoke
**/
public static FJTask par(FJTask[] tasks) {
return new Par(tasks);
}
/**
* A new Seq2(task1, task2)
, when executed,
* invokes task1 and then task2, in order.
* The class is a simple utility
* that makes it easier to create composite Tasks.
**/
public static class Seq2 extends FJTask {
protected final FJTask fst;
protected final FJTask snd;
public Seq2(FJTask task1, FJTask task2) {
fst = task1;
snd = task2;
}
public void run() {
FJTask.invoke(fst);
FJTask.invoke(snd);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke task1 and task2, in order
**/
public static FJTask seq(FJTask task1, FJTask task2) {
return new Seq2(task1, task2);
}
/**
* A new Par(task1, task2)
, when executed,
* runs task1 and task2 in parallel using coInvoke(task1, task2).
* The class is a simple utility
* that makes it easier to create composite Tasks.
**/
public static class Par2 extends FJTask {
protected final FJTask fst;
protected final FJTask snd;
public Par2(FJTask task1, FJTask task2) {
fst = task1;
snd = task2;
}
public void run() {
FJTask.coInvoke(fst, snd);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke task1 and task2, in parallel
**/
public static FJTask par(FJTask task1, FJTask task2) {
return new Par2(task1, task2);
}
}
libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/FJTaskRunner.java 0000644 0001750 0001750 00000075424 10730503124 030354 0 ustar twerner twerner /*
File: FJTaskRunner.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jan1999 dl First public release
13Jan1999 dl correct a stat counter update;
ensure inactive status on run termination;
misc minor cleaup
14Jan1999 dl Use random starting point in scan;
variable renamings.
18Jan1999 dl Runloop allowed to die on task exception;
remove useless timed join
22Jan1999 dl Rework scan to allow use of priorities.
6Feb1999 dl Documentation updates.
7Mar1999 dl Add array-based coInvoke
31Mar1999 dl Revise scan to remove need for NullTasks
27Apr1999 dl Renamed
23oct1999 dl Earlier detect of interrupt in scanWhileIdling
24nov1999 dl Now works on JVMs that do not properly
implement read-after-write of 2 volatiles.
*/
package org.logicalcobwebs.concurrent;
import java.util.Random;
/**
* Specialized Thread subclass for running FJTasks.
* * Each FJTaskRunner keeps FJTasks in a double-ended queue (DEQ). * Double-ended queues support stack-based operations * push and pop, as well as queue-based operations put and take. * Normally, threads run their own tasks. But they * may also steal tasks from each others DEQs. *
* The algorithms are minor variants of those used * in Cilk and * Hood, and * to a lesser extent * Filaments, * but are adapted to work in Java. *
* The two most important capabilities are: *
* Push task onto DEQ **
* If DEQ is not empty, * Pop a task and run it. * Else if any other DEQ is not empty, * Take ("steal") a task from it and run it. * Else if the entry queue for our group is not empty, * Take a task from it and run it. * Else if current thread is otherwise idling * If all threads are idling * Wait for a task to be put on group entry queue * Else * Yield or Sleep for a while, and then retry **
* Implementations of the underlying representations and operations * are geared for use on JVMs operating on multiple CPUs (although * they should of course work fine on single CPUs as well). *
* A possible snapshot of a FJTaskRunner's DEQ is: *
* 0 1 2 3 4 5 6 ... * +-----+-----+-----+-----+-----+-----+-----+-- * | | t | t | t | t | | | ... deq array * +-----+-----+-----+-----+-----+-----+-----+-- * ^ ^ * base top * (incremented (incremented * on take, on push * decremented decremented * on put) on pop) **
* FJTasks are held in elements of the DEQ.
* They are maintained in a bounded array that
* works similarly to a circular bounded buffer. To ensure
* visibility of stolen FJTasks across threads, the array elements
* must be volatile
.
* Using volatile rather than synchronizing suffices here since
* each task accessed by a thread is either one that it
* created or one that has never seen before. Thus we cannot
* encounter any staleness problems executing run methods,
* although FJTask programmers must be still sure to either synch or use
* volatile for shared data within their run methods.
*
* However, since there is no way * to declare an array of volatiles in Java, the DEQ elements actually * hold VolatileTaskRef objects, each of which in turn holds a * volatile reference to a FJTask. * Even with the double-indirection overhead of * volatile refs, using an array for the DEQ works out * better than linking them since fewer shared * memory locations need to be * touched or modified by the threads while using the DEQ. * Further, the double indirection may alleviate cache-line * sharing effects (which cannot otherwise be directly dealt with in Java). *
* The indices for the base
and top
of the DEQ
* are declared as volatile. The main contention point with
* multiple FJTaskRunner threads occurs when one thread is trying
* to pop its own stack while another is trying to steal from it.
* This is handled via a specialization of Dekker's algorithm,
* in which the popping thread pre-decrements top
,
* and then checks it against base
.
* To be conservative in the face of JVMs that only partially
* honor the specification for volatile, the pop proceeds
* without synchronization only if there are apparently enough
* items for both a simultaneous pop and take to succeed.
* It otherwise enters a
* synchronized lock to check if the DEQ is actually empty,
* if so failing. The stealing thread
* does almost the opposite, but is set up to be less likely
* to win in cases of contention: Steals always run under synchronized
* locks in order to avoid conflicts with other ongoing steals.
* They pre-increment base
, and then check against
* top
. They back out (resetting the base index
* and failing to steal) if the
* DEQ is empty or is about to become empty by an ongoing pop.
*
* A push operation can normally run concurrently with a steal. * A push enters a synch lock only if the DEQ appears full so must * either be resized or have indices adjusted due to wrap-around * of the bounded DEQ. The put operation always requires synchronization. *
* When a FJTaskRunner thread has no tasks of its own to run, * it tries to be a good citizen. * Threads run at lower priority while scanning for work. *
* If the task is currently waiting * via yield, the thread alternates scans (starting at a randomly * chosen victim) with Thread.yields. This is * well-behaved so long as the JVM handles Thread.yield in a * sensible fashion. (It need not. Thread.yield is so underspecified * that it is legal for a JVM to treat it as a no-op.) This also * keeps things well-behaved even if we are running on a uniprocessor * JVM using a simple cooperative threading model. *
* If a thread needing work is * is otherwise idle (which occurs only in the main runloop), and * there are no available tasks to steal or poll, it * instead enters into a sleep-based (actually timed wait(msec)) * phase in which it progressively sleeps for longer durations * (up to a maximum of FJTaskRunnerGroup.MAX_SLEEP_TIME, * currently 100ms) between scans. * If all threads in the group * are idling, they further progress to a hard wait phase, suspending * until a new task is entered into the FJTaskRunnerGroup entry queue. * A sleeping FJTaskRunner thread may be awakened by a new * task being put into the group entry queue or by another FJTaskRunner * becoming active, but not merely by some DEQ becoming non-empty. * Thus the MAX_SLEEP_TIME provides a bound for sleep durations * in cases where all but one worker thread start sleeping * even though there will eventually be work produced * by a thread that is taking a long time to place tasks in DEQ. * These sleep mechanics are handled in the FJTaskRunnerGroup class. *
* Composite operations such as taskJoin include heavy * manual inlining of the most time-critical operations * (mainly FJTask.invoke). * This opens up a few opportunities for further hand-optimizations. * Until Java compilers get a lot smarter, these tweaks * improve performance significantly enough for task-intensive * programs to be worth the poorer maintainability and code duplication. *
* Because they are so fragile and performance-sensitive, nearly * all methods are declared as final. However, nearly all fields * and methods are also declared as protected, so it is possible, * with much care, to extend functionality in subclasses. (Normally * you would also need to subclass FJTaskRunnerGroup.) *
* None of the normal java.lang.Thread class methods should ever be called * on FJTaskRunners. For this reason, it might have been nicer to * declare FJTaskRunner as a Runnable to run within a Thread. However, * this would have complicated many minor logistics. And since * no FJTaskRunner methods should normally be called from outside the * FJTask and FJTaskRunnerGroup classes either, this decision doesn't impact * usage. *
* You might think that layering this kind of framework on top of * Java threads, which are already several levels removed from raw CPU * scheduling on most systems, would lead to very poor performance. * But on the platforms * tested, the performance is quite good. *
[ Introduction to this package. ]
* @see FJTask
* @see FJTaskRunnerGroup
**/
public class FJTaskRunner extends Thread {
/** The group of which this FJTaskRunner is a member **/
protected final FJTaskRunnerGroup group;
/**
* Constructor called only during FJTaskRunnerGroup initialization
**/
protected FJTaskRunner(FJTaskRunnerGroup g) {
group = g;
victimRNG = new Random(System.identityHashCode(this));
runPriority = getPriority();
setDaemon(true);
}
/**
* Return the FJTaskRunnerGroup of which this thread is a member
**/
protected final FJTaskRunnerGroup getGroup() {
return group;
}
/* ------------ DEQ Representation ------------------- */
/**
* FJTasks are held in an array-based DEQ with INITIAL_CAPACITY
* elements. The DEQ is grown if necessary, but default value is
* normally much more than sufficient unless there are
* user programming errors or questionable operations generating
* large numbers of Tasks without running them.
* Capacities must be a power of two.
**/
protected static final int INITIAL_CAPACITY = 4096;
/**
* The maximum supported DEQ capacity.
* When exceeded, FJTaskRunner operations throw Errors
**/
protected static final int MAX_CAPACITY = 1 << 30;
/**
* An object holding a single volatile reference to a FJTask.
**/
protected final static class VolatileTaskRef {
/** The reference **/
protected volatile FJTask ref;
/** Set the reference **/
protected final void put(FJTask r) {
ref = r;
}
/** Return the reference **/
protected final FJTask get() {
return ref;
}
/** Return the reference and clear it **/
protected final FJTask take() {
FJTask r = ref;
ref = null;
return r;
}
/**
* Initialization utility for constructing arrays.
* Make an array of given capacity and fill it with
* VolatileTaskRefs.
**/
protected static VolatileTaskRef[] newArray(int cap) {
VolatileTaskRef[] a = new VolatileTaskRef[cap];
for (int k = 0; k < cap; k++) a[k] = new VolatileTaskRef();
return a;
}
}
/**
* The DEQ array.
**/
protected VolatileTaskRef[] deq = VolatileTaskRef.newArray(INITIAL_CAPACITY);
/** Current size of the task DEQ **/
protected int deqSize() {
return deq.length;
}
/**
* Current top of DEQ. Generally acts just like a stack pointer in an
* array-based stack, except that it circularly wraps around the
* array, as in an array-based queue. The value is NOT
* always kept within 0 ... deq.length
though.
* The current top element is always at top & (deq.length-1)
.
* To avoid integer overflow, top is reset down
* within bounds whenever it is noticed to be out out bounds;
* at worst when it is at 2 * deq.length
.
**/
protected volatile int top = 0;
/**
* Current base of DEQ. Acts like a take-pointer in an
* array-based bounded queue. Same bounds and usage as top.
**/
protected volatile int base = 0;
/**
* An extra object to synchronize on in order to
* achieve a memory barrier.
**/
protected final Object barrier = new Object();
/* ------------ Other BookKeeping ------------------- */
/**
* Record whether current thread may be processing a task
* (i.e., has been started and is not in an idle wait).
* Accessed, under synch, ONLY by FJTaskRunnerGroup, but the field is
* stored here for simplicity.
**/
protected boolean active = false;
/** Random starting point generator for scan() **/
protected final Random victimRNG;
/** Priority to use while scanning for work **/
protected int scanPriority = FJTaskRunnerGroup.DEFAULT_SCAN_PRIORITY;
/** Priority to use while running tasks **/
protected int runPriority;
/**
* Set the priority to use while scanning.
* We do not bother synchronizing access, since
* by the time the value is needed, both this FJTaskRunner
* and its FJTaskRunnerGroup will
* necessarily have performed enough synchronization
* to avoid staleness problems of any consequence.
**/
protected void setScanPriority(int pri) {
scanPriority = pri;
}
/**
* Set the priority to use while running tasks.
* Same usage and rationale as setScanPriority.
**/
protected void setRunPriority(int pri) {
runPriority = pri;
}
/**
* Compile-time constant for statistics gathering.
* Even when set, reported values may not be accurate
* since all are read and written without synchronization.
**/
static final boolean COLLECT_STATS = true;
// static final boolean COLLECT_STATS = false;
// for stat collection
/** Total number of tasks run **/
protected int runs = 0;
/** Total number of queues scanned for work **/
protected int scans = 0;
/** Total number of tasks obtained via scan **/
protected int steals = 0;
/* ------------ DEQ operations ------------------- */
/**
* Push a task onto DEQ.
* Called ONLY by current thread.
**/
protected final void push(final FJTask r) {
int t = top;
/*
This test catches both overflows and index wraps. It doesn't
really matter if base value is in the midst of changing in take.
As long as deq length is < 2^30, we are guaranteed to catch wrap in
time since base can only be incremented at most length times
between pushes (or puts).
*/
if (t < (base & (deq.length - 1)) + deq.length) {
deq[t & (deq.length - 1)].put(r);
top = t + 1;
} else // isolate slow case to increase chances push is inlined
slowPush(r); // check overflow and retry
}
/**
* Handle slow case for push
**/
protected synchronized void slowPush(final FJTask r) {
checkOverflow();
push(r); // just recurse -- this one is sure to succeed.
}
/**
* Enqueue task at base of DEQ.
* Called ONLY by current thread.
* This method is currently not called from class FJTask. It could be used
* as a faster way to do FJTask.start, but most users would
* find the semantics too confusing and unpredictable.
**/
protected final synchronized void put(final FJTask r) {
for (; ;) {
int b = base - 1;
if (top < b + deq.length) {
int newBase = b & (deq.length - 1);
deq[newBase].put(r);
base = newBase;
if (b != newBase) { // Adjust for index underflow
int newTop = top & (deq.length - 1);
if (newTop < newBase) newTop += deq.length;
top = newTop;
}
return;
} else {
checkOverflow();
// ... and retry
}
}
}
/**
* Return a popped task, or null if DEQ is empty.
* Called ONLY by current thread.
*
* This is not usually called directly but is * instead inlined in callers. This version differs from the * cilk algorithm in that pop does not fully back down and * retry in the case of potential conflict with take. It simply * rechecks under synch lock. This gives a preference * for threads to run their own tasks, which seems to * reduce flailing a bit when there are few tasks to run. **/ protected final FJTask pop() { /* Decrement top, to force a contending take to back down. */ int t = --top; /* To avoid problems with JVMs that do not properly implement read-after-write of a pair of volatiles, we conservatively grab without lock only if the DEQ appears to have at least two elements, thus guaranteeing that both a pop and take will succeed, even if the pre-increment in take is not seen by current thread. Otherwise we recheck under synch. */ if (base + 1 < t) return deq[t & (deq.length - 1)].take(); else return confirmPop(t); } /** * Check under synch lock if DEQ is really empty when doing pop. * Return task if not empty, else null. **/ protected final synchronized FJTask confirmPop(int provisionalTop) { if (base <= provisionalTop) return deq[provisionalTop & (deq.length - 1)].take(); else { // was empty /* Reset DEQ indices to zero whenever it is empty. This both avoids unnecessary calls to checkOverflow in push, and helps keep the DEQ from accumulating garbage */ top = base = 0; return null; } } /** * Take a task from the base of the DEQ. * Always called by other threads via scan() **/ protected final synchronized FJTask take() { /* Increment base in order to suppress a contending pop */ int b = base++; if (b < top) return confirmTake(b); else { // back out base = b; return null; } } /** * double-check a potential take **/ protected FJTask confirmTake(int oldBase) { /* Use a second (guaranteed uncontended) synch to serve as a barrier in case JVM does not properly process read-after-write of 2 volatiles */ synchronized (barrier) { if (oldBase < top) { /* We cannot call deq[oldBase].take here because of possible races when nulling out versus concurrent push operations. Resulting accumulated garbage is swept out periodically in checkOverflow, or more typically, just by keeping indices zero-based when found to be empty in pop, which keeps active region small and constantly overwritten. */ return deq[oldBase & (deq.length - 1)].get(); } else { base = oldBase; return null; } } } /** * Adjust top and base, and grow DEQ if necessary. * Called only while DEQ synch lock being held. * We don't expect this to be called very often. In most * programs using FJTasks, it is never called. **/ protected void checkOverflow() { int t = top; int b = base; if (t - b < deq.length - 1) { // check if just need an index reset int newBase = b & (deq.length - 1); int newTop = top & (deq.length - 1); if (newTop < newBase) newTop += deq.length; top = newTop; base = newBase; /* Null out refs to stolen tasks. This is the only time we can safely do it. */ int i = newBase; while (i != newTop && deq[i].ref != null) { deq[i].ref = null; i = (i - 1) & (deq.length - 1); } } else { // grow by doubling array int newTop = t - b; int oldcap = deq.length; int newcap = oldcap * 2; if (newcap >= MAX_CAPACITY) throw new Error("FJTask queue maximum capacity exceeded"); VolatileTaskRef[] newdeq = new VolatileTaskRef[newcap]; // copy in bottom half of new deq with refs from old deq for (int j = 0; j < oldcap; ++j) newdeq[j] = deq[b++ & (oldcap - 1)]; // fill top half of new deq with new refs for (int j = oldcap; j < newcap; ++j) newdeq[j] = new VolatileTaskRef(); deq = newdeq; base = 0; top = newTop; } } /* ------------ Scheduling ------------------- */ /** * Do all but the pop() part of yield or join, by * traversing all DEQs in our group looking for a task to * steal. If none, it checks the entry queue. *
* Since there are no good, portable alternatives, * we rely here on a mixture of Thread.yield and priorities * to reduce wasted spinning, even though these are * not well defined. We are hoping here that the JVM * does something sensible. * @param waitingFor if non-null, the current task being joined **/ protected void scan(final FJTask waitingFor) { FJTask task = null; // to delay lowering priority until first failure to steal boolean lowered = false; /* Circularly traverse from a random start index. This differs slightly from cilk version that uses a random index for each attempted steal. Exhaustive scanning might impede analytic tractablity of the scheduling policy, but makes it much easier to deal with startup and shutdown. */ FJTaskRunner[] ts = group.getArray(); int idx = victimRNG.nextInt(ts.length); for (int i = 0; i < ts.length; ++i) { FJTaskRunner t = ts[idx]; if (++idx >= ts.length) idx = 0; // circularly traverse if (t != null && t != this) { if (waitingFor != null && waitingFor.isDone()) { break; } else { if (COLLECT_STATS) ++scans; task = t.take(); if (task != null) { if (COLLECT_STATS) ++steals; break; } else if (isInterrupted()) { break; } else if (!lowered) { // if this is first fail, lower priority lowered = true; setPriority(scanPriority); } else { // otherwise we are at low priority; just yield yield(); } } } } if (task == null) { if (COLLECT_STATS) ++scans; task = group.pollEntryQueue(); if (COLLECT_STATS) if (task != null) ++steals; } if (lowered) setPriority(runPriority); if (task != null && !task.isDone()) { if (COLLECT_STATS) ++runs; task.run(); task.setDone(); } } /** * Same as scan, but called when current thread is idling. * It repeatedly scans other threads for tasks, * sleeping while none are available. *
* This differs from scan mainly in that
* since there is no reason to return to recheck any
* condition, we iterate until a task is found, backing
* off via sleeps if necessary.
**/
protected void scanWhileIdling() {
FJTask task = null;
boolean lowered = false;
long iters = 0;
FJTaskRunner[] ts = group.getArray();
int idx = victimRNG.nextInt(ts.length);
do {
for (int i = 0; i < ts.length; ++i) {
FJTaskRunner t = ts[idx];
if (++idx >= ts.length) idx = 0; // circularly traverse
if (t != null && t != this) {
if (COLLECT_STATS) ++scans;
task = t.take();
if (task != null) {
if (COLLECT_STATS) ++steals;
if (lowered) setPriority(runPriority);
group.setActive(this);
break;
}
}
}
if (task == null) {
if (isInterrupted())
return;
if (COLLECT_STATS) ++scans;
task = group.pollEntryQueue();
if (task != null) {
if (COLLECT_STATS) ++steals;
if (lowered) setPriority(runPriority);
group.setActive(this);
} else {
++iters;
// Check here for yield vs sleep to avoid entering group synch lock
if (iters >= group.SCANS_PER_SLEEP) {
group.checkActive(this, iters);
if (isInterrupted())
return;
} else if (!lowered) {
lowered = true;
setPriority(scanPriority);
} else {
yield();
}
}
}
} while (task == null);
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
}
/* ------------ composite operations ------------------- */
/**
* Main runloop
**/
public void run() {
try {
while (!interrupted()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
// inline FJTask.invoke
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
} else
scanWhileIdling();
}
} finally {
group.setInactive(this);
}
}
/**
* Execute a task in this thread. Generally called when current task
* cannot otherwise continue.
**/
protected final void taskYield() {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
} else
scan(null);
}
/**
* Process tasks until w is done.
* Equivalent to while(!w.isDone()) taskYield();
**/
protected final void taskJoin(final FJTask w) {
while (!w.isDone()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
if (task == w) return; // fast exit if we just ran w
}
} else
scan(w);
}
}
/**
* A specialized expansion of
* w.fork(); invoke(v); w.join();
**/
protected final void coInvoke(final FJTask w, final FJTask v) {
// inline push
int t = top;
if (t < (base & (deq.length - 1)) + deq.length) {
deq[t & (deq.length - 1)].put(w);
top = t + 1;
// inline invoke
if (!v.isDone()) {
if (COLLECT_STATS) ++runs;
v.run();
v.setDone();
}
// inline taskJoin
while (!w.isDone()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
if (task == w) return; // fast exit if we just ran w
}
} else
scan(w);
}
} else // handle non-inlinable cases
slowCoInvoke(w, v);
}
/**
* Backup to handle noninlinable cases of coInvoke
**/
protected void slowCoInvoke(final FJTask w, final FJTask v) {
push(w); // let push deal with overflow
FJTask.invoke(v);
taskJoin(w);
}
/**
* Array-based version of coInvoke
**/
protected final void coInvoke(FJTask[] tasks) {
int nforks = tasks.length - 1;
// inline bulk push of all but one task
int t = top;
if (nforks >= 0 && t + nforks < (base & (deq.length - 1)) + deq.length) {
for (int i = 0; i < nforks; ++i) {
deq[t++ & (deq.length - 1)].put(tasks[i]);
top = t;
}
// inline invoke of one task
FJTask v = tasks[nforks];
if (!v.isDone()) {
if (COLLECT_STATS) ++runs;
v.run();
v.setDone();
}
// inline taskJoins
for (int i = 0; i < nforks; ++i) {
FJTask w = tasks[i];
while (!w.isDone()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
} else
scan(w);
}
}
} else // handle non-inlinable cases
slowCoInvoke(tasks);
}
/**
* Backup to handle atypical or noninlinable cases of coInvoke
**/
protected void slowCoInvoke(FJTask[] tasks) {
for (int i = 0; i < tasks.length; ++i) push(tasks[i]);
for (int i = 0; i < tasks.length; ++i) taskJoin(tasks[i]);
}
}
libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/FJTaskRunnerGroup.java 0000644 0001750 0001750 00000052140 10730503124 031357 0 ustar twerner twerner /*
File: FJTaskRunnerGroup.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jan1999 dl First public release
12Jan1999 dl made getActiveCount public; misc minor cleanup.
14Jan1999 dl Added executeTask
20Jan1999 dl Allow use of priorities; reformat stats
6Feb1999 dl Lazy thread starts
27Apr1999 dl Renamed
*/
package org.logicalcobwebs.concurrent;
/**
* A stripped down analog of a ThreadGroup used for
* establishing and managing FJTaskRunner threads.
* ThreadRunnerGroups serve as the control boundary separating
* the general world of normal threads from the specialized world
* of FJTasks.
*
* By intent, this class does not subclass java.lang.ThreadGroup, and * does not support most methods found in ThreadGroups, since they * would make no sense for FJTaskRunner threads. In fact, the class * does not deal with ThreadGroups at all. If you want to restrict * a FJTaskRunnerGroup to a particular ThreadGroup, you can create * it from within that ThreadGroup. *
* The main contextual parameter for a FJTaskRunnerGroup is * the group size, established in the constructor. * Groups must be of a fixed size. * There is no way to dynamically increase or decrease the number * of threads in an existing group. *
* In general, the group size should be equal to the number
* of CPUs on the system. (Unfortunately, there is no portable
* means of automatically detecting the number of CPUs on a JVM, so there is
* no good way to automate defaults.) In principle, when
* FJTasks are used for computation-intensive tasks, having only
* as many threads as CPUs should minimize bookkeeping overhead
* and contention, and so maximize throughput. However, because
* FJTaskRunners lie atop Java threads, and in turn operating system
* thread support and scheduling policies,
* it is very possible that using more threads
* than CPUs will improve overall throughput even though it adds
* to overhead. This will always be so if FJTasks are I/O bound.
* So it may pay to experiment a bit when tuning on particular platforms.
* You can also use setRunPriorities
to either
* increase or decrease the priorities of active threads, which
* may interact with group size choice.
*
* In any case, overestimating group sizes never * seriously degrades performance (at least within reasonable bounds). * You can also use a value * less than the number of CPUs in order to reserve processing * for unrelated threads. *
* There are two general styles for using a FJTaskRunnerGroup. * You can create one group per entire program execution, for example * as a static singleton, and use it for all parallel tasks: *
* class Tasks { * static FJTaskRunnerGroup group; * public void initialize(int groupsize) { * group = new FJTaskRunnerGroup(groupSize); * } * // ... * } ** Alternatively, you can make new groups on the fly and use them only for * particular task sets. This is more flexible,, * and leads to more controllable and deterministic execution patterns, * but it encounters greater overhead on startup. Also, to reclaim * system resources, you should * call
FJTaskRunnerGroup.interruptAll
when you are done
* using one-shot groups. Otherwise, because FJTaskRunners set
* Thread.isDaemon
* status, they will not normally be reclaimed until program termination.
*
* The main supported methods are execute
,
* which starts a task processed by FJTaskRunner threads,
* and invoke
, which starts one and waits for completion.
* For example, you might extend the above FJTasks
* class to support a task-based computation, say, the
* Fib
class from the FJTask
documentation:
*
* class Tasks { // continued * // ... * static int fib(int n) { * try { * Fib f = new Fib(n); * group.invoke(f); * return f.getAnswer(); * } * catch (InterruptedException ex) { * throw new Error("Interrupted during computation"); * } * } * } **
* Method stats()
can be used to monitor performance.
* Both FJTaskRunnerGroup and FJTaskRunner may be compiled with
* the compile-time constant COLLECT_STATS set to false. In this
* case, various simple counts reported in stats() are not collected.
* On platforms tested,
* this leads to such a tiny performance improvement that there is
* very little motivation to bother.
*
*
[ Introduction to this package. ] *
* @see FJTask * @see FJTaskRunner **/ public class FJTaskRunnerGroup implements Executor { /** The threads in this group **/ protected final FJTaskRunner[] threads; /** Group-wide queue for tasks entered via execute() **/ protected final LinkedQueue entryQueue = new LinkedQueue(); /** Number of threads that are not waiting for work **/ protected int activeCount = 0; /** Number of threads that have been started. Used to avoid unecessary contention during startup of task sets. **/ protected int nstarted = 0; /** * Compile-time constant. If true, various counts of * runs, waits, etc., are maintained. These are NOT * updated with synchronization, so statistics reports * might not be accurate. **/ static final boolean COLLECT_STATS = true; // static final boolean COLLECT_STATS = false; // for stats /** The time at which this ThreadRunnerGroup was constructed **/ long initTime = 0; /** Total number of executes or invokes **/ int entries = 0; static final int DEFAULT_SCAN_PRIORITY = Thread.MIN_PRIORITY + 1; /** * Create a FJTaskRunnerGroup with the indicated number * of FJTaskRunner threads. Normally, the best size to use is * the number of CPUs on the system. *
* The threads in a FJTaskRunnerGroup are created with their
* isDaemon status set, so do not normally need to be
* shut down manually upon program termination.
**/
public FJTaskRunnerGroup(int groupSize) {
threads = new FJTaskRunner[groupSize];
initializeThreads();
initTime = System.currentTimeMillis();
}
/**
* Arrange for execution of the given task
* by placing it in a work queue. If the argument
* is not of type FJTask, it is embedded in a FJTask via
* FJTask.Wrap
.
* @exception InterruptedException if current Thread is
* currently interrupted
**/
public void execute(Runnable r) throws InterruptedException {
if (r instanceof FJTask) {
entryQueue.put((FJTask) r);
} else {
entryQueue.put(new FJTask.Wrap(r));
}
signalNewTask();
}
/**
* Specialized form of execute called only from within FJTasks
**/
public void executeTask(FJTask t) {
try {
entryQueue.put(t);
signalNewTask();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* Start a task and wait it out. Returns when the task completes.
* @exception InterruptedException if current Thread is
* interrupted before completion of the task.
**/
public void invoke(Runnable r) throws InterruptedException {
InvokableFJTask w = new InvokableFJTask(r);
entryQueue.put(w);
signalNewTask();
w.awaitTermination();
}
/**
* Try to shut down all FJTaskRunner threads in this group
* by interrupting them all. This method is designed
* to be used during cleanup when it is somehow known
* that all threads are idle.
* FJTaskRunners only
* check for interruption when they are not otherwise
* processing a task (and its generated subtasks,
* if any), so if any threads are active, shutdown may
* take a while, and may lead to unpredictable
* task processing.
**/
public void interruptAll() {
// paranoically interrupt current thread last if in group.
Thread current = Thread.currentThread();
boolean stopCurrent = false;
for (int i = 0; i < threads.length; ++i) {
Thread t = threads[i];
if (t == current)
stopCurrent = true;
else
t.interrupt();
}
if (stopCurrent)
current.interrupt();
}
/**
* Set the priority to use while a FJTaskRunner is
* polling for new tasks to perform. Default
* is currently Thread.MIN_PRIORITY+1. The value
* set may not go into effect immediately, but
* will be used at least the next time a thread scans for work.
**/
public synchronized void setScanPriorities(int pri) {
for (int i = 0; i < threads.length; ++i) {
FJTaskRunner t = threads[i];
t.setScanPriority(pri);
if (!t.active) t.setPriority(pri);
}
}
/**
* Set the priority to use while a FJTaskRunner is
* actively running tasks. Default
* is the priority that was in effect by the thread that
* constructed this FJTaskRunnerGroup. Setting this value
* while threads are running may momentarily result in
* them running at this priority even when idly waiting for work.
**/
public synchronized void setRunPriorities(int pri) {
for (int i = 0; i < threads.length; ++i) {
FJTaskRunner t = threads[i];
t.setRunPriority(pri);
if (t.active) t.setPriority(pri);
}
}
/** Return the number of FJTaskRunner threads in this group **/
public int size() {
return threads.length;
}
/**
* Return the number of threads that are not idly waiting for work.
* Beware that even active threads might not be doing any useful
* work, but just spinning waiting for other dependent tasks.
* Also, since this is just a snapshot value, some tasks
* may be in the process of becoming idle.
**/
public synchronized int getActiveCount() {
return activeCount;
}
/**
* Prints various snapshot statistics to System.out.
*
* Cautions: Some statistics are updated and gathered * without synchronization, * so may not be accurate. However, reported counts may be considered * as lower bounds of actual values. * Some values may be zero if classes are compiled * with COLLECT_STATS set to false. (FJTaskRunner and FJTaskRunnerGroup * classes can be independently compiled with different values of * COLLECT_STATS.) Also, the counts are maintained as ints so could * overflow in exceptionally long-lived applications. *
* These statistics can be useful when tuning algorithms or diagnosing * problems. For example: *
* This is not treated as a user-tunable parameter because * good values do not appear to vary much across JVMs or * applications. Its main role is to help avoid some * useless spinning and contention during task startup. **/ static final long SCANS_PER_SLEEP = 15; /** * The maximum time (in msecs) to sleep when a thread is idle, * yet others are not, so may eventually generate work that * the current thread can steal. This value reflects the maximum time * that a thread may sleep when it possibly should not, because there * are other active threads that might generate work. In practice, * designs in which some threads become stalled because others * are running yet not generating tasks are not likely to work * well in this framework anyway, so the exact value does not matter * too much. However, keeping it in the sub-second range does * help smooth out startup and shutdown effects. **/ static final long MAX_SLEEP_TIME = 100; /** * Set active status of thread t to false, and * then wait until: (a) there is a task in the entry * queue, or (b) other threads are active, or (c) the current * thread is interrupted. Upon return, it * is not certain that there will be work available. * The thread must itself check. *
* The main underlying reason * for these mechanics is that threads do not * signal each other when they add elements to their queues. * (This would add to task overhead, reduce locality. * and increase contention.) * So we must rely on a tamed form of polling. However, tasks * inserted into the entry queue do result in signals, so * tasks can wait on these if all of them are otherwise idle. **/ protected synchronized void checkActive(FJTaskRunner t, long scans) { setInactive(t); try { // if nothing available, do a hard wait if (activeCount == 0 && entryQueue.peek() == null) { wait(); } else { // If there is possibly some work, // sleep for a while before rechecking long msecs = scans / SCANS_PER_SLEEP; if (msecs > MAX_SLEEP_TIME) msecs = MAX_SLEEP_TIME; int nsecs = (msecs == 0) ? 1 : 0; // forces shortest possible sleep wait(msecs, nsecs); } } catch (InterruptedException ex) { notify(); // avoid lost notifies on interrupts Thread.currentThread().interrupt(); } } /* ------------ Utility methods ------------- */ /** * Start or wake up any threads waiting for work **/ protected synchronized void signalNewTask() { if (COLLECT_STATS) ++entries; if (nstarted < threads.length) threads[nstarted++].start(); else notify(); } /** * Create all FJTaskRunner threads in this group. **/ protected void initializeThreads() { for (int i = 0; i < threads.length; ++i) threads[i] = new FJTaskRunner(this); } /** * Wrap wait/notify mechanics around a task so that * invoke() can wait it out **/ protected static final class InvokableFJTask extends FJTask { protected final Runnable wrapped; protected boolean terminated = false; protected InvokableFJTask(Runnable r) { wrapped = r; } public void run() { try { if (wrapped instanceof FJTask) FJTask.invoke((FJTask) (wrapped)); else wrapped.run(); } finally { setTerminated(); } } protected synchronized void setTerminated() { terminated = true; notifyAll(); } protected synchronized void awaitTermination() throws InterruptedException { while (!terminated) wait(); } } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/FutureResult.java 0000644 0001750 0001750 00000014367 10730503124 030510 0 ustar twerner twerner /* File: FutureResult.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 30Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; import java.lang.reflect.InvocationTargetException; /** * A class maintaining a single reference variable serving as the result * of an operation. The result cannot be accessed until it has been set. *
* Sample Usage
*
* class ImageRenderer { Image render(byte[] raw); } * class App { * Executor executor = ... * ImageRenderer renderer = ... * void display(byte[] rawimage) { * try { * FutureResult futureImage = new FutureResult(); * Runnable command = futureImage.setter(new Callable() { * public Object call() { return renderer.render(rawImage); } * }); * executor.execute(command); * drawBorders(); // do other things while executing * drawCaption(); * drawImage((Image)(futureImage.get())); // use future * } * catch (InterruptedException ex) { return; } * catch (InvocationTargetException ex) { cleanup(); return; } * } * } **
[ Introduction to this package. ] * @see Executor **/ public class FutureResult { /** The result of the operation **/ protected Object value_ = null; /** Status -- true after first set **/ protected boolean ready_ = false; /** the exception encountered by operation producing result **/ protected InvocationTargetException exception_ = null; /** * Create an initially unset FutureResult **/ public FutureResult() { } /** * Return a Runnable object that, when run, will set the result value. * @param function - a Callable object whose result will be * held by this FutureResult. * @return A Runnable object that, when run, will call the * function and (eventually) set the result. **/ public Runnable setter(final Callable function) { return new Runnable() { public void run() { try { set(function.call()); } catch (Throwable ex) { setException(ex); } } }; } /** internal utility: either get the value or throw the exception **/ protected Object doGet() throws InvocationTargetException { if (exception_ != null) throw exception_; else return value_; } /** * Access the reference, waiting if necessary until it is ready. * @return current value * @exception InterruptedException if current thread has been interrupted * @exception InvocationTargetException if the operation * producing the value encountered an exception. **/ public synchronized Object get() throws InterruptedException, InvocationTargetException { while (!ready_) wait(); return doGet(); } /** * Wait at most msecs to access the reference. * @return current value * @exception TimeoutException if not ready after msecs * @exception InterruptedException if current thread has been interrupted * @exception InvocationTargetException if the operation * producing the value encountered an exception. **/ public synchronized Object timedGet(long msecs) throws TimeoutException, InterruptedException, InvocationTargetException { long startTime = (msecs <= 0) ? 0 : System.currentTimeMillis(); long waitTime = msecs; if (ready_) return doGet(); else if (waitTime <= 0) throw new TimeoutException(msecs); else { for (; ;) { wait(waitTime); if (ready_) return doGet(); else { waitTime = msecs - (System.currentTimeMillis() - startTime); if (waitTime <= 0) throw new TimeoutException(msecs); } } } } /** * Set the reference, and signal that it is ready. It is not * considered an error to set the value more than once, * but it is not something you would normally want to do. * @param newValue The value that will be returned by a subsequent get(); **/ public synchronized void set(Object newValue) { value_ = newValue; ready_ = true; notifyAll(); } /** * Set the exception field, also setting ready status. * @param ex The exception. It will be reported out wrapped * within an InvocationTargetException **/ public synchronized void setException(Throwable ex) { exception_ = new InvocationTargetException(ex); ready_ = true; notifyAll(); } /** * Get the exception, or null if there isn't one (yet). * This does not wait until the future is ready, so should * ordinarily only be called if you know it is. * @return the exception encountered by the operation * setting the future, wrapped in an InvocationTargetException **/ public synchronized InvocationTargetException getException() { return exception_; } /** * Return whether the reference or exception have been set. * @return true if has been set. else false **/ public synchronized boolean isReady() { return ready_; } /** * Access the reference, even if not ready * @return current value **/ public synchronized Object peek() { return value_; } /** * Clear the value and exception and set to not-ready, * allowing this FutureResult to be reused. This is not * particularly recommended and must be done only * when you know that no other object is depending on the * properties of this FutureResult. **/ public synchronized void clear() { value_ = null; exception_ = null; ready_ = false; } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/LinkedNode.java 0000644 0001750 0001750 00000001612 10730503124 030040 0 ustar twerner twerner /* File: LinkedNode.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version 25may2000 dl Change class access to public 26nov2001 dl Added no-arg constructor, all public access. */ package org.logicalcobwebs.concurrent; /** A standard linked list node used in various queue classes **/ public class LinkedNode { public Object value; public LinkedNode next; public LinkedNode() { } public LinkedNode(Object x) { value = x; } public LinkedNode(Object x, LinkedNode n) { value = x; next = n; } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/LinkedQueue.java 0000644 0001750 0001750 00000013007 10730503124 030240 0 ustar twerner twerner /* File: LinkedQueue.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version 25aug1998 dl added peek 10dec1998 dl added isEmpty 10oct1999 dl lock on node object to ensure visibility */ package org.logicalcobwebs.concurrent; /** * A linked list based channel implementation. * The algorithm avoids contention between puts * and takes when the queue is not empty. * Normally a put and a take can proceed simultaneously. * (Although it does not allow multiple concurrent puts or takes.) * This class tends to perform more efficently than * other Channel implementations in producer/consumer * applications. *
[ Introduction to this package. ] **/ public class LinkedQueue implements Channel { /** * Dummy header node of list. The first actual node, if it exists, is always * at head_.next. After each take, the old first node becomes the head. **/ protected LinkedNode head_; /** * Helper monitor for managing access to last node. **/ protected final Object putLock_ = new Object(); /** * The last node of list. Put() appends to list, so modifies last_ **/ protected LinkedNode last_; /** * The number of threads waiting for a take. * Notifications are provided in put only if greater than zero. * The bookkeeping is worth it here since in reasonably balanced * usages, the notifications will hardly ever be necessary, so * the call overhead to notify can be eliminated. **/ protected int waitingForTake_ = 0; public LinkedQueue() { head_ = new LinkedNode(null); last_ = head_; } /** Main mechanics for put/offer **/ protected void insert(Object x) { synchronized (putLock_) { LinkedNode p = new LinkedNode(x); synchronized (last_) { last_.next = p; last_ = p; } if (waitingForTake_ > 0) putLock_.notify(); } } /** Main mechanics for take/poll **/ protected synchronized Object extract() { synchronized (head_) { Object x = null; LinkedNode first = head_.next; if (first != null) { x = first.value; first.value = null; head_ = first; } return x; } } public void put(Object x) throws InterruptedException { if (x == null) throw new IllegalArgumentException(); if (Thread.interrupted()) throw new InterruptedException(); insert(x); } public boolean offer(Object x, long msecs) throws InterruptedException { if (x == null) throw new IllegalArgumentException(); if (Thread.interrupted()) throw new InterruptedException(); insert(x); return true; } public Object take() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); // try to extract. If fail, then enter wait-based retry loop Object x = extract(); if (x != null) return x; else { synchronized (putLock_) { try { ++waitingForTake_; for (; ;) { x = extract(); if (x != null) { --waitingForTake_; return x; } else { putLock_.wait(); } } } catch (InterruptedException ex) { --waitingForTake_; putLock_.notify(); throw ex; } } } } public Object peek() { synchronized (head_) { LinkedNode first = head_.next; if (first != null) return first.value; else return null; } } public boolean isEmpty() { synchronized (head_) { return head_.next == null; } } public Object poll(long msecs) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Object x = extract(); if (x != null) return x; else { synchronized (putLock_) { try { long waitTime = msecs; long start = (msecs <= 0) ? 0 : System.currentTimeMillis(); ++waitingForTake_; for (; ;) { x = extract(); if (x != null || waitTime <= 0) { --waitingForTake_; return x; } else { putLock_.wait(waitTime); waitTime = msecs - (System.currentTimeMillis() - start); } } } catch (InterruptedException ex) { --waitingForTake_; putLock_.notify(); throw ex; } } } } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/Puttable.java 0000644 0001750 0001750 00000005076 10730503124 027614 0 ustar twerner twerner /* File: Puttable.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * This interface exists to enable stricter type checking * for channels. A method argument or instance variable * in a producer object can be declared as only a Puttable * rather than a Channel, in which case a Java compiler * will disallow take operations. *
* Full method descriptions appear in the Channel interface. *
[ Introduction to this package. ] * @see Channel * @see Takable **/ public interface Puttable { /** * Place item in the channel, possibly waiting indefinitely until * it can be accepted. Channels implementing the BoundedChannel * subinterface are generally guaranteed to block on puts upon * reaching capacity, but other implementations may or may not block. * @param item the element to be inserted. Should be non-null. * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case the element is guaranteed not * to be inserted. Otherwise, on normal return, the element is guaranteed * to have been inserted. **/ public void put(Object item) throws InterruptedException; /** * Place item in channel only if it can be accepted within * msecs milliseconds. The time bound is interpreted in * a coarse-grained, best-effort fashion. * @param item the element to be inserted. Should be non-null. * @param msecs the number of milliseconds to wait. If less than * or equal to zero, the method does not perform any timed waits, * but might still require * access to a synchronization lock, which can impose unbounded * delay if there is a lot of contention for the channel. * @return true if accepted, else false * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case the element is guaranteed not * to be inserted (i.e., is equivalent to a false return). **/ public boolean offer(Object item, long msecs) throws InterruptedException; } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/ReadWriteLock.java 0000644 0001750 0001750 00000004544 10730503124 030532 0 ustar twerner twerner /* File: ReadWriteLock.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * ReadWriteLocks maintain a pair of associated locks. * The readLock may be held simultanously by multiple * reader threads, so long as there are no writers. The writeLock * is exclusive. ReadWrite locks are generally preferable to * plain Sync locks or synchronized methods in cases where: *
* Standard usage: *
* class X { * ReadWriteLock rw; * // ... * * public void read() throws InterruptedException { * rw.readLock().acquire(); * try { * // ... do the read * } * finally { * rw.readlock().release() * } * } * * * public void write() throws InterruptedException { * rw.writeLock().acquire(); * try { * // ... do the write * } * finally { * rw.writelock().release() * } * } * } ** @see Sync *
[ Introduction to this package. ] **/ public interface ReadWriteLock { /** get the readLock **/ Sync readLock(); /** get the writeLock **/ Sync writeLock(); } ././@LongLink 0000000 0000000 0000000 00000000145 00000000000 011565 L ustar root root libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/ReaderPreferenceReadWriteLock.java libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/ReaderPreferenceReadWriteLock.java0000644 0001750 0001750 00000002001 10730503124 033636 0 ustar twerner twerner /* File: ReaderPreferenceReadWriteLock.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * A ReadWriteLock that prefers waiting readers over * waiting writers when there is contention. The range of applicability * of this class is very limited. In the majority of situations, * writer preference locks provide more reasonable semantics. * *
[ Introduction to this package. ] **/ public class ReaderPreferenceReadWriteLock extends WriterPreferenceReadWriteLock { protected boolean allowReader() { return activeWriter_ == null; } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/Sync.java 0000644 0001750 0001750 00000025574 10730503124 026755 0 ustar twerner twerner /* File: Sync.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version 5Aug1998 dl Added some convenient time constants */ package org.logicalcobwebs.concurrent; /** * Main interface for locks, gates, and conditions. *
* Sync objects isolate waiting and notification for particular * logical states, resource availability, events, and the like that are * shared across multiple threads. Use of Syncs sometimes * (but by no means always) adds flexibility and efficiency * compared to the use of plain java monitor methods * and locking, and are sometimes (but by no means always) * simpler to program with. *
* * Most Syncs are intended to be used primarily (although * not exclusively) in before/after constructions such as: *
* class X { * Sync gate; * // ... * * public void m() { * try { * gate.acquire(); // block until condition holds * try { * // ... method body * } * finally { * gate.release() * } * } * catch (InterruptedException ex) { * // ... evasive action * } * } * * public void m2(Sync cond) { // use supplied condition * try { * if (cond.attempt(10)) { // try the condition for 10 ms * try { * // ... method body * } * finally { * cond.release() * } * } * } * catch (InterruptedException ex) { * // ... evasive action * } * } * } ** Syncs may be used in somewhat tedious but more flexible replacements * for built-in Java synchronized blocks. For example: *
* class HandSynched { * private double state_ = 0.0; * private final Sync lock; // use lock type supplied in constructor * public HandSynched(Sync l) { lock = l; } * * public void changeState(double d) { * try { * lock.acquire(); * try { state_ = updateFunction(d); } * finally { lock.release(); } * } * catch(InterruptedException ex) { } * } * * public double getState() { * double d = 0.0; * try { * lock.acquire(); * try { d = accessFunction(state_); } * finally { lock.release(); } * } * catch(InterruptedException ex){} * return d; * } * private double updateFunction(double d) { ... } * private double accessFunction(double d) { ... } * } ** If you have a lot of such methods, and they take a common * form, you can standardize this using wrappers. Some of these * wrappers are standardized in LockedExecutor, but you can make others. * For example: *
* class HandSynchedV2 { * private double state_ = 0.0; * private final Sync lock; // use lock type supplied in constructor * public HandSynchedV2(Sync l) { lock = l; } * * protected void runSafely(Runnable r) { * try { * lock.acquire(); * try { r.run(); } * finally { lock.release(); } * } * catch (InterruptedException ex) { // propagate without throwing * Thread.currentThread().interrupt(); * } * } * * public void changeState(double d) { * runSafely(new Runnable() { * public void run() { state_ = updateFunction(d); } * }); * } * // ... * } **
* One reason to bother with such constructions is to use deadlock- * avoiding back-offs when dealing with locks involving multiple objects. * For example, here is a Cell class that uses attempt to back-off * and retry if two Cells are trying to swap values with each other * at the same time. *
* class Cell { * long value; * Sync lock = ... // some sync implementation class * void swapValue(Cell other) { * for (;;) { * try { * lock.acquire(); * try { * if (other.lock.attempt(100)) { * try { * long t = value; * value = other.value; * other.value = t; * return; * } * finally { other.lock.release(); } * } * } * finally { lock.release(); } * } * catch (InterruptedException ex) { return; } * } * } * } **
* Here is an even fancier version, that uses lock re-ordering * upon conflict: *
* class Cell { * long value; * Sync lock = ...; * private static boolean trySwap(Cell a, Cell b) { * a.lock.acquire(); * try { * if (!b.lock.attempt(0)) * return false; * try { * long t = a.value; * a.value = b.value; * b.value = t; * return true; * } * finally { other.lock.release(); } * } * finally { lock.release(); } * return false; * } * * void swapValue(Cell other) { * try { * while (!trySwap(this, other) && * !tryswap(other, this)) * Thread.sleep(1); * } * catch (InterruptedException ex) { return; } * } *} **
* Interruptions are in general handled as early as possible. * Normally, InterruptionExceptions are thrown * in acquire and attempt(msec) if interruption * is detected upon entry to the method, as well as in any * later context surrounding waits. * However, interruption status is ignored in release(); *
* Timed versions of attempt report failure via return value. * If so desired, you can transform such constructions to use exception * throws via *
* if (!c.attempt(timeval)) throw new TimeoutException(timeval); **
* The TimoutSync wrapper class can be used to automate such usages. *
* All time values are expressed in milliseconds as longs, which have a maximum * value of Long.MAX_VALUE, or almost 300,000 centuries. It is not * known whether JVMs actually deal correctly with such extreme values. * For convenience, some useful time values are defined as static constants. *
* All implementations of the three Sync methods guarantee to
* somehow employ Java synchronized
methods or blocks,
* and so entail the memory operations described in JLS
* chapter 17 which ensure that variables are loaded and flushed
* within before/after constructions.
*
* Syncs may also be used in spinlock constructions. Although * it is normally best to just use acquire(), various forms * of busy waits can be implemented. For a simple example * (but one that would probably never be preferable to using acquire()): *
* class X { * Sync lock = ... * void spinUntilAcquired() throws InterruptedException { * // Two phase. * // First spin without pausing. * int purespins = 10; * for (int i = 0; i < purespins; ++i) { * if (lock.attempt(0)) * return true; * } * // Second phase - use timed waits * long waitTime = 1; // 1 millisecond * for (;;) { * if (lock.attempt(waitTime)) * return true; * else * waitTime = waitTime * 3 / 2 + 1; // increase 50% * } * } * } **
* In addition pure synchronization control, Syncs * may be useful in any context requiring before/after methods. * For example, you can use an ObservableSync * (perhaps as part of a LayeredSync) in order to obtain callbacks * before and after each method invocation for a given class. *
*
[ Introduction to this package. ] **/ public interface Sync { /** * Wait (possibly forever) until successful passage. * Fail only upon interuption. Interruptions always result in * `clean' failures. On failure, you can be sure that it has not * been acquired, and that no * corresponding release should be performed. Conversely, * a normal return guarantees that the acquire was successful. **/ public void acquire() throws InterruptedException; /** * Wait at most msecs to pass; report whether passed. *
* The method has best-effort semantics: * The msecs bound cannot * be guaranteed to be a precise upper bound on wait time in Java. * Implementations generally can only attempt to return as soon as possible * after the specified bound. Also, timers in Java do not stop during garbage * collection, so timeouts can occur just because a GC intervened. * So, msecs arguments should be used in * a coarse-grained manner. Further, * implementations cannot always guarantee that this method * will return at all without blocking indefinitely when used in * unintended ways. For example, deadlocks may be encountered * when called in an unintended context. *
* @param msecs the number of milleseconds to wait. * An argument less than or equal to zero means not to wait at all. * However, this may still require * access to a synchronization lock, which can impose unbounded * delay if there is a lot of contention among threads. * @return true if acquired **/ public boolean attempt(long msecs) throws InterruptedException; /** * Potentially enable others to pass. *
* Because release does not raise exceptions, * it can be used in `finally' clauses without requiring extra * embedded try/catch blocks. But keep in mind that * as with any java method, implementations may * still throw unchecked exceptions such as Error or NullPointerException * when faced with uncontinuable errors. However, these should normally * only be caught by higher-level error handlers. **/ public void release(); /** One second, in milliseconds; convenient as a time-out value **/ public static final long ONE_SECOND = 1000; /** One minute, in milliseconds; convenient as a time-out value **/ public static final long ONE_MINUTE = 60 * ONE_SECOND; /** One hour, in milliseconds; convenient as a time-out value **/ public static final long ONE_HOUR = 60 * ONE_MINUTE; /** One day, in milliseconds; convenient as a time-out value **/ public static final long ONE_DAY = 24 * ONE_HOUR; /** One week, in milliseconds; convenient as a time-out value **/ public static final long ONE_WEEK = 7 * ONE_DAY; /** One year in milliseconds; convenient as a time-out value **/ // Not that it matters, but there is some variation across // standard sources about value at msec precision. // The value used is the same as in java.util.GregorianCalendar public static final long ONE_YEAR = (long) (365.2425 * ONE_DAY); /** One century in milliseconds; convenient as a time-out value **/ public static final long ONE_CENTURY = 100 * ONE_YEAR; } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/SynchronizedInt.java 0000644 0001750 0001750 00000013476 10730503124 031171 0 ustar twerner twerner /* File: SynchronizedInt.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 19Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * A class useful for offloading synch for int instance variables. * *
[ Introduction to this package. ] **/ public class SynchronizedInt extends SynchronizedVariable implements Comparable, Cloneable { protected int value_; /** * Make a new SynchronizedInt with the given initial value, * and using its own internal lock. **/ public SynchronizedInt(int initialValue) { super(); value_ = initialValue; } /** * Make a new SynchronizedInt with the given initial value, * and using the supplied lock. **/ public SynchronizedInt(int initialValue, Object lock) { super(lock); value_ = initialValue; } /** * Return the current value **/ public final int get() { synchronized (lock_) { return value_; } } /** * Set to newValue. * @return the old value **/ public int set(int newValue) { synchronized (lock_) { int old = value_; value_ = newValue; return old; } } /** * Set value to newValue only if it is currently assumedValue. * @return true if successful **/ public boolean commit(int assumedValue, int newValue) { synchronized (lock_) { boolean success = (assumedValue == value_); if (success) value_ = newValue; return success; } } /** * Atomically swap values with another SynchronizedInt. * Uses identityHashCode to avoid deadlock when * two SynchronizedInts attempt to simultaneously swap with each other. * (Note: Ordering via identyHashCode is not strictly guaranteed * by the language specification to return unique, orderable * values, but in practice JVMs rely on them being unique.) * @return the new value **/ public int swap(SynchronizedInt other) { if (other == this) return get(); SynchronizedInt fst = this; SynchronizedInt snd = other; if (System.identityHashCode(fst) > System.identityHashCode(snd)) { fst = other; snd = this; } synchronized (fst.lock_) { synchronized (snd.lock_) { fst.set(snd.set(fst.get())); return get(); } } } /** * Increment the value. * @return the new value **/ public int increment() { synchronized (lock_) { return ++value_; } } /** * Decrement the value. * @return the new value **/ public int decrement() { synchronized (lock_) { return --value_; } } /** * Add amount to value (i.e., set value += amount) * @return the new value **/ public int add(int amount) { synchronized (lock_) { return value_ += amount; } } /** * Subtract amount from value (i.e., set value -= amount) * @return the new value **/ public int subtract(int amount) { synchronized (lock_) { return value_ -= amount; } } /** * Multiply value by factor (i.e., set value *= factor) * @return the new value **/ public synchronized int multiply(int factor) { synchronized (lock_) { return value_ *= factor; } } /** * Divide value by factor (i.e., set value /= factor) * @return the new value **/ public int divide(int factor) { synchronized (lock_) { return value_ /= factor; } } /** * Set the value to the negative of its old value * @return the new value **/ public int negate() { synchronized (lock_) { value_ = -value_; return value_; } } /** * Set the value to its complement * @return the new value **/ public int complement() { synchronized (lock_) { value_ = ~value_; return value_; } } /** * Set value to value & b. * @return the new value **/ public int and(int b) { synchronized (lock_) { value_ = value_ & b; return value_; } } /** * Set value to value | b. * @return the new value **/ public int or(int b) { synchronized (lock_) { value_ = value_ | b; return value_; } } /** * Set value to value ^ b. * @return the new value **/ public int xor(int b) { synchronized (lock_) { value_ = value_ ^ b; return value_; } } public int compareTo(int other) { int val = get(); return (val < other) ? -1 : (val == other) ? 0 : 1; } public int compareTo(SynchronizedInt other) { return compareTo(other.get()); } public int compareTo(Object other) { return compareTo((SynchronizedInt) other); } public boolean equals(Object other) { if (other != null && other instanceof SynchronizedInt) return get() == ((SynchronizedInt) other).get(); else return false; } public int hashCode() { return get(); } public String toString() { return String.valueOf(get()); } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/SynchronizedVariable.java 0000644 0001750 0001750 00000017512 10730503124 032157 0 ustar twerner twerner /* File: SynchronizedVariable.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 30Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * Base class for simple, small classes * maintaining single values that are always accessed * and updated under synchronization. Since defining them for only * some types seemed too arbitrary, they exist for all basic types, * although it is hard to imagine uses for some. *
* These classes mainly exist so that you do not have to go to the * trouble of writing your own miscellaneous classes and methods * in situations including: *
final
. This
* helps avoid the need to synchronize just to obtain the reference
* to the synchronized variable itself.
*
* static
variables. It almost
* always works out better to rely on synchronization internal
* to these objects, rather than class locks.
* * While they cannot, by nature, share much code, * all of these classes work in the same way. *
* Construction
* Synchronized variables are always constructed holding an
* initial value of the associated type. Constructors also
* establish the lock to use for all methods:
*
* Update methods
* Each class supports several kinds of update methods:
*
set
method that sets to a new value and returns
* previous value. For example, for a SynchronizedBoolean b,
* boolean old = b.set(true)
performs a test-and-set.
* *
commit
method that sets to new value only
* if currently holding a given value.
*
* For example, here is a class that uses an optimistic update
* loop to recompute a count variable represented as a
* SynchronizedInt.
* * class X { * private final SynchronizedInt count = new SynchronizedInt(0); * * static final int MAX_RETRIES = 1000; * * public boolean recomputeCount() throws InterruptedException { * for (int i = 0; i < MAX_RETRIES; ++i) { * int current = count.get(); * int next = compute(current); * if (count.commit(current, next)) * return true; * else if (Thread.interrupted()) * throw new InterruptedException(); * } * return false; * } * int compute(int l) { ... some kind of computation ... } * } **
*
swap
method that atomically swaps with another
* object of the same class using a deadlock-avoidance strategy.
* *
* Guarded methods
* All Waitable
subclasses provide notifications on
* every value update, and support guarded methods of the form
* when
predicate, that wait until the
* predicate hold, then optionally run any Runnable action
* within the lock, and then return. All types support:
*
* Other methods
* This class implements Executor, and provides an execute
* method that runs the runnable within the lock.
*
* All classes except SynchronizedRef and WaitableRef implement
* Cloneable
and Comparable
.
* Implementations of the corresponding
* methods either use default mechanics, or use methods that closely
* correspond to their java.lang analogs. SynchronizedRef does not
* implement any of these standard interfaces because there are
* many cases where it would not make sense. However, you can
* easily make simple subclasses that add the appropriate declarations.
*
*
* * * *
[ Introduction to this package. ] **/ public class SynchronizedVariable implements Executor { protected final Object lock_; /** Create a SynchronizedVariable using the supplied lock **/ public SynchronizedVariable(Object lock) { lock_ = lock; } /** Create a SynchronizedVariable using itself as the lock **/ public SynchronizedVariable() { lock_ = this; } /** * Return the lock used for all synchronization for this object **/ public Object getLock() { return lock_; } /** * If current thread is not interrupted, execute the given command * within this object's lock **/ public void execute(Runnable command) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); synchronized (lock_) { command.run(); } } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/Takable.java 0000644 0001750 0001750 00000004500 10730503124 027366 0 ustar twerner twerner /* File: Takable.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version */ package org.logicalcobwebs.concurrent; /** * This interface exists to enable stricter type checking * for channels. A method argument or instance variable * in a consumer object can be declared as only a Takable * rather than a Channel, in which case a Java compiler * will disallow put operations. *
* Full method descriptions appear in the Channel interface. *
[ Introduction to this package. ] * @see Channel * @see Puttable **/ public interface Takable { /** * Return and remove an item from channel, * possibly waiting indefinitely until * such an item exists. * @return some item from the channel. Different implementations * may guarantee various properties (such as FIFO) about that item * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case state of the channel is unchanged. * **/ public Object take() throws InterruptedException; /** * Return and remove an item from channel only if one is available within * msecs milliseconds. The time bound is interpreted in a coarse * grained, best-effort fashion. * @param msecs the number of milliseconds to wait. If less than * or equal to zero, the operation does not perform any timed waits, * but might still require * access to a synchronization lock, which can impose unbounded * delay if there is a lot of contention for the channel. * @return some item, or null if the channel is empty. * @exception InterruptedException if the current thread has * been interrupted at a point at which interruption * is detected, in which case state of the channel is unchanged * (i.e., equivalent to a false return). **/ public Object poll(long msecs) throws InterruptedException; } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/TimeoutException.java 0000644 0001750 0001750 00000002602 10730503124 031331 0 ustar twerner twerner /* File: TimeoutException.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 29Jun1998 dl Create public version 4Aug1998 dl Change to extend InterruptedException */ package org.logicalcobwebs.concurrent; /** * Thrown by synchronization classes that report * timeouts via exceptions. The exception is treated * as a form (subclass) of InterruptedException. This both * simplifies handling, and conceptually reflects the fact that * timed-out operations are artificially interrupted by timers. **/ public class TimeoutException extends InterruptedException { /** * The approximate time that the operation lasted before * this timeout exception was thrown. **/ public final long duration; /** * Constructs a TimeoutException with given duration value. **/ public TimeoutException(long time) { duration = time; } /** * Constructs a TimeoutException with the * specified duration value and detail message. */ public TimeoutException(long time, String message) { super(message); duration = time; } } ././@LongLink 0000000 0000000 0000000 00000000145 00000000000 011565 L ustar root root libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/WriterPreferenceReadWriteLock.java libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/WriterPreferenceReadWriteLock.java0000644 0001750 0001750 00000025244 10730503124 033726 0 ustar twerner twerner /* File: WriterPreferenceReadWriteLock.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 11Jun1998 dl Create public version 5Aug1998 dl replaced int counters with longs 25aug1998 dl record writer thread 3May1999 dl add notifications on interrupt/timeout */ package org.logicalcobwebs.concurrent; /** * A ReadWriteLock that prefers waiting writers over * waiting readers when there is contention. This class * is adapted from the versions described in CPJ, improving * on the ones there a bit by segregating reader and writer * wait queues, which is typically more efficient. *
* The locks are NOT reentrant. In particular, * even though it may appear to usually work OK, * a thread holding a read lock should not attempt to * re-acquire it. Doing so risks lockouts when there are * also waiting writers. *
[ Introduction to this package. ] **/ public class WriterPreferenceReadWriteLock implements ReadWriteLock { protected long activeReaders_ = 0; protected Thread activeWriter_ = null; protected long waitingReaders_ = 0; protected long waitingWriters_ = 0; protected final ReaderLock readerLock_ = new ReaderLock(); protected final WriterLock writerLock_ = new WriterLock(); public Sync writeLock() { return writerLock_; } public Sync readLock() { return readerLock_; } /* A bunch of small synchronized methods are needed to allow communication from the Lock objects back to this object, that serves as controller */ protected synchronized void cancelledWaitingReader() { --waitingReaders_; } protected synchronized void cancelledWaitingWriter() { --waitingWriters_; } /** Override this method to change to reader preference **/ protected boolean allowReader() { return activeWriter_ == null && waitingWriters_ == 0; } protected synchronized boolean startRead() { boolean allowRead = allowReader(); if (allowRead) ++activeReaders_; return allowRead; } protected synchronized boolean startWrite() { // The allowWrite expression cannot be modified without // also changing startWrite, so is hard-wired boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0); if (allowWrite) activeWriter_ = Thread.currentThread(); return allowWrite; } /* Each of these variants is needed to maintain atomicity of wait counts during wait loops. They could be made faster by manually inlining each other. We hope that compilers do this for us though. */ protected synchronized boolean startReadFromNewReader() { boolean pass = startRead(); if (!pass) ++waitingReaders_; return pass; } protected synchronized boolean startWriteFromNewWriter() { boolean pass = startWrite(); if (!pass) ++waitingWriters_; return pass; } protected synchronized boolean startReadFromWaitingReader() { boolean pass = startRead(); if (pass) --waitingReaders_; return pass; } protected synchronized boolean startWriteFromWaitingWriter() { boolean pass = startWrite(); if (pass) --waitingWriters_; return pass; } /** * Called upon termination of a read. * Returns the object to signal to wake up a waiter, or null if no such **/ protected synchronized Signaller endRead() { if (--activeReaders_ == 0 && waitingWriters_ > 0) return writerLock_; else return null; } /** * Called upon termination of a write. * Returns the object to signal to wake up a waiter, or null if no such **/ protected synchronized Signaller endWrite() { activeWriter_ = null; if (waitingReaders_ > 0 && allowReader()) return readerLock_; else if (waitingWriters_ > 0) return writerLock_; else return null; } /** * Reader and Writer requests are maintained in two different * wait sets, by two different objects. These objects do not * know whether the wait sets need notification since they * don't know preference rules. So, each supports a * method that can be selected by main controlling object * to perform the notifications. This base class simplifies mechanics. **/ protected abstract class Signaller { // base for ReaderLock and WriterLock abstract void signalWaiters(); } protected class ReaderLock extends Signaller implements Sync { public void acquire() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); InterruptedException ie = null; synchronized (this) { if (!startReadFromNewReader()) { for (; ;) { try { ReaderLock.this.wait(); if (startReadFromWaitingReader()) return; } catch (InterruptedException ex) { cancelledWaitingReader(); ie = ex; break; } } } } if (ie != null) { // fall through outside synch on interrupt. // This notification is not really needed here, // but may be in plausible subclasses writerLock_.signalWaiters(); throw ie; } } public void release() { Signaller s = endRead(); if (s != null) s.signalWaiters(); } synchronized void signalWaiters() { ReaderLock.this.notifyAll(); } public boolean attempt(long msecs) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); InterruptedException ie = null; synchronized (this) { if (msecs <= 0) return startRead(); else if (startReadFromNewReader()) return true; else { long waitTime = msecs; long start = System.currentTimeMillis(); for (; ;) { try { ReaderLock.this.wait(waitTime); } catch (InterruptedException ex) { cancelledWaitingReader(); ie = ex; break; } if (startReadFromWaitingReader()) return true; else { waitTime = msecs - (System.currentTimeMillis() - start); if (waitTime <= 0) { cancelledWaitingReader(); break; } } } } } // safeguard on interrupt or timeout: writerLock_.signalWaiters(); if (ie != null) throw ie; else return false; // timed out } } protected class WriterLock extends Signaller implements Sync { public void acquire() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); InterruptedException ie = null; synchronized (this) { if (!startWriteFromNewWriter()) { for (; ;) { try { WriterLock.this.wait(); if (startWriteFromWaitingWriter()) return; } catch (InterruptedException ex) { cancelledWaitingWriter(); WriterLock.this.notify(); ie = ex; break; } } } } if (ie != null) { // Fall through outside synch on interrupt. // On exception, we may need to signal readers. // It is not worth checking here whether it is strictly necessary. readerLock_.signalWaiters(); throw ie; } } public void release() { Signaller s = endWrite(); if (s != null) s.signalWaiters(); } synchronized void signalWaiters() { WriterLock.this.notify(); } public boolean attempt(long msecs) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); InterruptedException ie = null; synchronized (this) { if (msecs <= 0) return startWrite(); else if (startWriteFromNewWriter()) return true; else { long waitTime = msecs; long start = System.currentTimeMillis(); for (; ;) { try { WriterLock.this.wait(waitTime); } catch (InterruptedException ex) { cancelledWaitingWriter(); WriterLock.this.notify(); ie = ex; break; } if (startWriteFromWaitingWriter()) return true; else { waitTime = msecs - (System.currentTimeMillis() - start); if (waitTime <= 0) { cancelledWaitingWriter(); WriterLock.this.notify(); break; } } } } } readerLock_.signalWaiters(); if (ie != null) throw ie; else return false; // timed out } } } libproxool-java-0.9.1.orig/src/java/org/logicalcobwebs/concurrent/package.html 0000644 0001750 0001750 00000000554 10730503124 027446 0 ustar twerner twerner
Concurrency utilities.
Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code.