/**
* SAMOA - PROTOCOL FRAMEWORK
* Copyright (C) 2005 Olivier Rütti (EPFL) (olivier.rutti@a3.epfl.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package seqSamoa;
import java.util.LinkedList;
import framework.libraries.FlowControl;
/**
* The <CODE>SamoaFlowControl</CODE> implements a mechanism to control the
* number of "messages" in the stack and so to avoid memory overflows
* due to overload.
*/
public class SamoaFlowControl implements FlowControl {
protected int[] threshold;
protected int[] used;
protected boolean[] blocked;
protected int nextKey = 0;
protected LinkedList<Integer> freeKeys;
/**
* Constructor
*
* @param keys
* number of resources where we need to have a flow control
*/
public SamoaFlowControl(int keys) {
threshold = new int[keys];
used = new int[keys];
blocked = new boolean[keys];
freeKeys = new LinkedList<Integer>();
}
/**
* Block the "key" resource.
*
* @param key
* the "key" of the resource
*/
public void block(int key) {
blocked[key] = true;
}
/**
* Release the "key" resource.
*
* @param key
* the "key" of the resource
*/
synchronized public void release(int key) {
if (blocked[key])
notifyAll();
blocked[key] = false;
}
/**
* Wait until there is an amount available for each registered resources
*/
public synchronized void enter() {
while (blocked()) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException("Broken wait()!!!");
}
}
}
/**
* Get a key number for a resource
*
* @return a free key
*/
public int getFreshKey() {
int freshKey;
if (!freeKeys.isEmpty())
freshKey = freeKeys.removeFirst();
else if (nextKey < used.length)
freshKey = nextKey++;
else
throw new RuntimeException("Key overflow!!!");
threshold[freshKey] = 1;
used[freshKey] = 0;
blocked[freshKey] = false;
return freshKey;
}
/**
* Release a key number for a resource
*/
public void releaseKey(int key) {
threshold[key] = 1;
used[key] = 0;
blocked[key] = false;
freeKeys.add(key);
}
// Is there any resources in each protocol
private boolean blocked() {
boolean block = false;
for (int i = 0; i < nextKey && !block; i++) {
block = block || (used[i] > threshold[i]) || blocked[i];
}
return block;
}
}