package hj.lang;
import hj.runtime.wsh.Activity;
import hj.runtime.wsh.FinishScope;
import hj.runtime.wsh.phaser.PhaserRegModeImpl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author bchase
*
*/
public class phaser {
private int yetToSignal;
private HashMap<Activity, Integer> signalers;
private HashMap<Activity, Integer> waiters;
private phaserMode mode;
private Condition phaseAdvance;
private ReentrantLock lock;
private FinishScope scope;
private Activity singleActivity;
private Condition singleHolder;
public phaser() {
mode= phaserMode.SIG_WAIT_SINGLE;
setUp();
}
public phaser(phaserMode mode) {
this.mode = mode;
setUp();
}
private void setUp() {
yetToSignal = 0;
signalers = new HashMap<Activity, Integer>();
waiters = new HashMap<Activity, Integer>();
lock = new ReentrantLock();
phaseAdvance = lock.newCondition();
singleActivity=null;
singleHolder = lock.newCondition();
/* Add the parent of the phaser to the finish scope it belongs to
* The phaser has the parent in it to prevent it from advancing to the next phase
* before the finish scope hits end scope
* When the parent hits stopFinish(), the parent will deregister itself so that
* the phaser can now advance to the next phase
*/
Activity parent = (Activity) Thread.currentThread();
scope = parent.getCurrentFinishScope();
parent.addPhaser(new PhaserRegModeImpl(this,phaserMode.SIG_WAIT));
scope.addPhaser(this);
registerSignaler(parent);
registerWaiter(parent);
}
public final void registerSignaler(Activity newParty) {
try {
lock.lock();
if (newParty == null) return;
if (signalers.containsKey(newParty) == false) {
signalers.put(newParty, new Integer(0));
yetToSignal++;
}
} finally {
lock.unlock();
}
}
public final void registerWaiter(Activity newParty) {
try {
lock.lock();
if (newParty == null) return;
if (waiters.containsKey(newParty) == false) {
waiters.put(newParty, new Integer(0));
}
} finally {
lock.unlock();
}
}
public void unregisterSignaler(Activity existingParty) {
try {
lock.lock();
if (existingParty == null) return;
if (signalers.containsKey(existingParty)) {
int value = signalers.get(existingParty);
if (value == 0) yetToSignal--;
signalers.remove(existingParty);
if (checkAdvancePhase()) {
advancePhase();
}
}
} finally {
lock.unlock();
}
}
public void unregisterWaiter(Activity existingParty) {
try {
lock.lock();
if (existingParty == null) return;
if (waiters.containsKey(existingParty)) {
waiters.remove(existingParty);
}
} finally {
lock.unlock();
}
}
//Advance phase --
// This methods should:
// -Decrement the signal value of all signalers
// -For each signaler that has a new signal value of
// zero, yetToSignal is incremented by one.
// -Increment all the wait values
// -Notify all blocked waiters that phase has advanced
private void advancePhase() {
try {
lock.lock();
for (Map.Entry<Activity, Integer> entry : signalers.entrySet()) {
Activity signaler = entry.getKey();
int signalValue = entry.getValue();
signalers.put(signaler, signalValue-1);
signalValue--;
if (signalValue == 0) yetToSignal++;
}
for (Map.Entry<Activity, Integer> entry : waiters.entrySet()) {
Activity waiter = entry.getKey();
int waitValue = entry.getValue();
waiters.put(waiter, waitValue+1);
}
phaseAdvance.signalAll();
} finally {
lock.unlock();
}
}
public void phSignal(Activity signaler) {
try {
lock.lock();
if (signalers.containsKey(signaler)) {
int value = signalers.get(signaler);
signalers.put(signaler, value+1);
if (value == 0) yetToSignal--;
if (checkAdvancePhase()) {
advancePhase();
}
}
} finally {
lock.unlock();
}
}
public void phWait(Activity waiter) {
try {
lock.lock();
if (waiter == null) return;
//if (waiters.containsKey(waiter)) {
while (waiters.get(waiter) <= 0) {
phaseAdvance.await();
}
int waitValue = waiters.get(waiter);
waiters.put(waiter, waitValue-1);
//}
} catch (InterruptedException ex) {
Logger.getLogger(phaser.class.getName()).log(Level.SEVERE, null, ex);
} finally {
lock.unlock();
}
}
// Check to see if the phaser needs to advance or not
private boolean checkAdvancePhase() {
if (yetToSignal != 0)
return false;
if (singleActivity==null)
return true;
// If there is an activity assigned as the single, release it
// The activity will advance the phase after the single statement
singleHolder.signal();
return false;
}
public boolean phSignalSingle(Activity single) {
try {
lock.lock();
boolean isFirstSingle=false;
if (singleActivity==null) {
singleActivity=single;
isFirstSingle=true;
}
phSignal(single);
return isFirstSingle;
} finally {
lock.unlock();
}
}
public void holdSingle(Activity single) {
try {
lock.lock();
while (single == singleActivity && yetToSignal>0) {
singleHolder.await();
}
} catch (InterruptedException ex) {
Logger.getLogger(phaser.class.getName()).log(Level.SEVERE, null, ex);
} finally {
lock.unlock();
}
}
public void phWaitSingle(Activity single) {
try {
lock.lock();
if (single == singleActivity) {
singleActivity=null;
if (checkAdvancePhase()) {
advancePhase();
}
}
phWait(single);
} finally {
lock.unlock();
}
}
public phaserMode getMode() {
return mode;
}
}