package coordination; import java.util.*; //!!! /** * The Coordinator class provides the basic functionality for synchronizing * and coordinating different threads upon entering and exiting methods. * It can be used in two different ways: * 1) by instantiating regular coordinator objects that are used by aspects; or * 2) by extending it (sub-classing) with coordinator aspects. *

* Method invocations are the smallest units for defining critical sections * and pre-conditions. The use of coordinators, either regular objects or aspect * instances, should always end up by invoking guardedEntry(...) in a * before weave and guardedExit(...) in an after weave for all methods that * need coordination. guardedEntry and guardedExit are the methods that * actually manage the synchronization and coordination constraints given * by their parameters and by pre-existent exclusion markers. *

* The synchronization of threads for the execution of critical section * methods in an object is done by marking those methods as self- and/or * mutually-exclusive (addSelfex, addMutex). * Just by itself, addSelfex("M") does not enforce the self-exclusion * of method M - enforcement is done by invoking guardedEntry before * M is executed. Similarly, addMutex(new String[] {"M1", "M2"}) does * not enforce the mutual exclusion between methods M1 and M2. *

* A guardedEntry on a method that has been marked as self-exclusive * ensures that the method is executed in the invoked object by only one thread * at a time. A guardedEntry on a method that has been marked has mutually- * exclusive with other methods ensures that the execution of that method * by a thread in the invoked object temporarily blocks the execution by * other threads of the methods that are in the same mutex set. *

* The coordination of threads, i.e. their explicit suspension and * resumption, is done through the use of pre-conditions and coordination * actions that are passed as parameters to guardedEntry and guardedExit * with the form of anonymous classes. */ public abstract aspect Coordinator { private Hashtable methods = null; private Vector exclusions = null; abstract protected pointcut synchronizationPoint(); public Coordinator() { methods = new Hashtable(); exclusions = new Vector(5); } before (): synchronizationPoint() { this.guardedEntry(thisJoinPointStaticPart.getSignature().getName()); } after (): synchronizationPoint() { this.guardedExit(thisJoinPointStaticPart.getSignature().getName()); } /** * Takes a multi-part method name (eg "BoundedBuffer.put") * and marks that method as self-exclusive. * No checks are made with respect to the existence of the method * whose name is given. */ public synchronized void addSelfex(String methName) { Selfex sex = new Selfex (methName); // update db of all exclusions in this coordinator exclusions.addElement(sex); // update local info in method Method aMeth = getOrSetMethod(methName); aMeth.addExclusion(sex); } /** * Takes a multi-part method name (e.g. "BoundedBuffer.put") * and removes that method from the list of self-exclusive methods. */ public synchronized void removeSelfex(String methName) { for (int i = 0; i < exclusions.size(); i++) { Exclusion sex = (Exclusion)exclusions.elementAt(i); if ((sex instanceof Selfex) && (((Selfex)sex).methodName.equals(methName))) { // update db of all exclusions in this coordinator exclusions.removeElementAt(i); // update local info in method Method aMeth = getOrSetMethod(methName); aMeth.removeExclusion(sex); } } } /** * Takes an array of multi-part method names and marks those * methods as mutually exclusive. * No checks are made with respect to the existence of the methods * whose names are given. */ public synchronized void addMutex(String[] methNames) { Mutex mux = new Mutex(methNames); // update db of all exclusions in this coordinator exclusions.addElement(mux); // update local info in each method for (int i = 0; i < methNames.length; i++) { Method aMeth = getOrSetMethod(methNames[i]); aMeth.addExclusion(mux); } } /** * Takes an array of multi-part method names that correspond * to an existing mutex set and remove the mutual exclusion constraint. * If the given mutex set does not exist, removeMutex does nothing. */ public synchronized void removeMutex(String[] methNames) { for (int i = 0; i < exclusions.size(); i++) { Exclusion mux = (Exclusion)exclusions.elementAt(i); if (mux instanceof Mutex) { boolean same = true; for (int j = 0; j < methNames.length; j++) if (!methNames[j].equals(((Mutex)mux).methodNames[j])) same = false; if (same) { // update db of all exclusions in this coordinator exclusions.removeElementAt(i); // update local info in each method involved for (int j = 0; j < methNames.length; j++) { Method aMeth = getOrSetMethod(methNames[j]); aMeth.removeExclusion(mux); } } } } } /** * This method is the guard for enforcing all synchronization and * coordination constraints of a given method, and it should be called * just before the method is executed. * In this form, only the method name is given. The only constraints * checked are the exclusion constraints. * If the method was previousely marked as selfex (through addSelfex), * guardedEntry ensures that the method is executed only when no other * thread is executing it. * If the method was previousely marked as being in one or more mutex * sets, guardedEntry ensures that the method is executed only when no other * thread is executing any of the methods with which the give method is * mutexed. */ public synchronized void guardedEntry(String methName) { guardedEntry(methName, new Condition() { public boolean checkit() { return true; } }, null); } /** * Just like guardedEntry(String methName), but the given method is executed * only when the given condition is true. * guardedEntry is the guard for enforcing all synchronization and * coordination constraints of a given method, and it should be called * just before the method is executed. * In this form, the method name is given along with a condition. * The constraints checked are the exclusion constraints and whether * the given condition is true. * If the method was previousely marked as selfex (through addSelfex), * guardedEntry ensures that the method is executed only when no other * thread is executing it. * If the method was previousely marked as being in one or more mutex * sets, guardedEntry ensures that the method is executed only when no other * thread is executing any of the methods with which the give method is * mutexed. * If the condition is false, guardedEntry suspends the current thread. * That thread remains suspended until the condition becomes true, in * which case all constraints are rechecked before the method is executed. * When all exclusion constraints are checked and the given condition is * true, the given method is executed. */ public synchronized void guardedEntry(String methName, Condition condition) { guardedEntry(methName, condition, null); } /** * Just like guardedEntry(String methName), but with an additional * coordination action that is executed before the given method is * executed. * guardedEntry is the guard for enforcing all synchronization and * coordination constraints of a given method, and it should be called * just before the method is executed. * In this form, the method name is given along with a coordination action. * The only constraints checked are the exclusion constraints. * If the method was previousely marked as selfex (through addSelfex), * guardedEntry ensures that the method is executed only when no other * thread is executing it. * If the method was previousely marked as being in one or more mutex * sets, guardedEntry ensures that the method is executed only when no other * thread is executing any of the methods with which the give method is * mutexed. * The given coordination action is executed just before the given method * is executed. */ public synchronized void guardedEntry(String methName, CoordinationAction action) { guardedEntry(methName, new Condition() { public boolean checkit() { return true; } }, action); } /** * Just like guardedEntry(String methName), but the given method is executed * only when the given condition is true; the additional * coordination action that is executed before the given method is * executed. * guardedEntry is the guard for enforcing all synchronization and * coordination constraints of a given method, and it should be called * just before the method is executed. * In this form, the method name is given along with a condition and * a coordination action. * The constraints checked are the exclusion constraints and whether the * given condition is true. * If the method was previousely marked as selfex (through addSelfex), * guardedEntry ensures that the method is executed only when no other * thread is executing it. * If the method was previousely marked as being in one or more mutex * sets, guardedEntry ensures that the method is executed only when no other * thread is executing any of the methods with which the give method is * mutexed. * If the condition is false, guardedEntry suspends the current thread. * That thread remains suspended until the condition becomes true, in * which case all constraints are rechecked before the method is executed. * When all exclusion constraints are checked and the given condition is * true, the given method is executed. * The given coordination action is executed just before the given method * is executed. */ public synchronized void guardedEntry(String methName, Condition condition, CoordinationAction action) { Method aMeth = getOrSetMethod(methName); boolean canGo = false; // test pre-conditions for entering the method while (!canGo) { canGo = true; for (int i = 0; i < aMeth.exes.size() && canGo; i++) if (!((Exclusion)aMeth.exes.elementAt(i)).testExclusion(aMeth.name)) { canGo = false; } if (canGo && !condition.checkit()) { canGo = false; } if (!canGo) try { wait(); } catch (InterruptedException e) { } } // OK. enterMethod(aMeth, action); } /** * This method is similar to guardedEntry, but it takes * an additional parameter - the milliseconds after which any suspension * will abort with a timeout. */ public synchronized void guardedEntryWithTimeout(String methName, long millis) throws TimeoutException { guardedEntryWithTimeout(methName, new Condition() { public boolean checkit() { return true; } }, null, millis); } /** * This method is similar to guardedEntry, but it takes * an additional parameter - the milliseconds after which any suspension * will abort with a timeout. */ public synchronized void guardedEntryWithTimeout(String methName, Condition condition, long millis) throws TimeoutException { guardedEntryWithTimeout(methName, condition, null, millis); } /** * This method is similar to guardedEntry, but it takes * an additional parameter - the milliseconds after which any suspension * will abort with a timeout. */ public synchronized void guardedEntryWithTimeout(String methName, CoordinationAction action, long millis) throws TimeoutException { guardedEntryWithTimeout(methName, new Condition() { public boolean checkit() { return true; } }, action, millis); } /** * This method is similar to guardedEntry, but it takes * an additional parameter - the milliseconds after which any suspension * will abort with a timeout. */ public synchronized void guardedEntryWithTimeout(String methName, Condition condition, CoordinationAction action, long millis) throws TimeoutException { Method aMeth = getOrSetMethod(methName); boolean canGo = false; long waitTime = millis; long startTime = System.currentTimeMillis(); // test pre-conditions for entering the method while (!canGo) { canGo = true; for (int i = 0; i < aMeth.exes.size() && canGo; i++) if ((!((Exclusion)aMeth.exes.elementAt(i)).testExclusion(aMeth.name)) || (!condition.checkit())) { canGo = false; } if (!canGo) { try { wait(waitTime); } catch (InterruptedException e) {} long now = System.currentTimeMillis(); long timeSoFar = now - startTime; if (timeSoFar >= millis) // timeout! throw new TimeoutException(timeSoFar); else // adjust time waitTime = millis - timeSoFar; } } // OK. enterMethod(aMeth, action); } /** * This method provides the means for updating all synchronization and * coordination state after the execution of a given method, and it should be * called after the method is executed. * In this form, only the method name is given. * The synchronization state for self- and mutual-exclusion is * automatically upadted. */ public synchronized void guardedExit(String methName) { guardedExit(methName, null); } /** * Just like guardedExit(String methName) but with an additional * coordination action that is executed. * guardedExit provides the means for updating all synchronization and * coordination state after the execution of a given method, and it should be * called after the method is executed. * In this form, the method name is given along with a coordination action. * The synchronization state for self- and mutual-exclusion is * automatically upadted. * The given coordination action is executed. */ public synchronized void guardedExit(String methName, CoordinationAction action) { Method aMeth = getOrSetMethod(methName); for (int i = 0; i < aMeth.exes.size(); i++) ((Exclusion)aMeth.exes.elementAt(i)).exitExclusion(methName); if (action != null) action.doit(); notifyAll(); } private Method getOrSetMethod(String methName) { Method aMeth = null; if (!methods.containsKey(methName)) { methods.put(methName, (aMeth = new Method(methName))); } else { aMeth = (Method) methods.get(methName); } return aMeth; } private void enterMethod(Method aMeth, CoordinationAction action) { for (int i = 0; i < aMeth.exes.size(); i++) ((Exclusion)aMeth.exes.elementAt(i)).enterExclusion(aMeth.name); if (action != null) action.doit(); } } class Method { String name; Vector exes = new Vector(3); Method(String n) { name = n; } void addExclusion(Exclusion ex) { exes.addElement(ex); } void removeExclusion(Exclusion ex) { for (int i = 0; i < exes.size(); i++) { if (exes.elementAt(i) == ex) exes.removeElementAt(i); } } }