//
// $Source: /nfs/elm/d3/home/cur/djb1/java/javat/RCS/Alternative.java,v $
//
// $Id: Alternative.java,v 1.1 1997/06/23 17:04:34 djb1 Exp $
//
// Alternative - ALT implementation for Object_Channels
//
// (C) Copyright 1997 Peter Welch
// University of Kent at Canterbury
//
// package occam;
public class Alternative {
/*
DOCUMENTATION
This mechanism is based upon the data structures and algorithms implemented
by micro-code in the transputer. It is exactly the same algorithm as used
by the KRoC kernel and by the SPoC translator.
An Alternative object is part of the ALTing process and records the status
of the Alt.
1. (PRI) ALT on a channel array (with optional pre-conditions)
It's `select' method is called by the ALTing process and returns an index
for a ready Channel if-and-only-if one of the Channels becomes ready. If
no Channel is ready, it waits (non-busilly) until one is. The parameters
to `select' are an array of Channels over which to ALT (plus an optional
array of boolean pre-conditions, settable at run-time). The `select'
implements a PRI ALT over the channel array, with highest priority going
to channel index zero.
2. (PRI) ALT on a channel array and a timeout (with optional pre-conditions)
Versions of `select' also allow ALTing a channel array against a timeout
(with and without pre-conditions). The timeout guard has lowest priority.
The timeout setting is relative to the time of ALTing and not an absolute
time (as in occam). To get timeouts at an absolute time, read the time now
and compute the time remaining -- use the latter in the `select'. Because
of the primitives provided by Java, there are two versions of each of these
timeout ALTs: one which sets the timeout in terms of milliseconds and one
in terms of milliseconds plus nanoseconds.
The select method returns an value in the range 0 to the channel array
length inclusive. If the value is a legal channel array index, then that
is the channel selected. If the value is equal to the size of the channel
array (and is not, therefore, an array index), the timeout has occured.
3. (PRI) ALT on a channel array and SKIP (with optional pre-conditions)
Finally, there are versions of `select' also to allow ALTing a channel
array against a SKIP guard (with a complusory pre-condition on the SKIP
and an optional set on the channels). The SKIP guard has lowest priority,
which means these versions may be used to poll the channel array.
The select method returns an value in the range 0 to the channel array
length inclusive. If the value is a legal channel array index, then that
is the channel selected. If the value is equal to the size of the channel
array (and is not, therefore, an array index), none of the channels were
ready.
This `select' method operates exactly like similar routines for ALT
provided in INMOS or 3L parallel C (e.g. `procAltList' or
`alt_wait_vec' respectively).
As with those, it is the programmer's responsibility to ensure that
the Channel indicated by the selected index is actually used.
An Alternative object is "passive", containing no threads of its own.
For any Channel, there may only be one process ALTing on it, although there
may be many processes sharing the other end.
The `schedule' method is not public and is called only from an enabled
Channel object (by the outputting process).
*/
// Constants
private static final int INACTIVE = 0;
private static final int ENABLING = 1;
private static final int WAITING = 2;
private static final int READY = 3;
// object state
private int state = INACTIVE;
// (PRI) ALT on a channel array
public synchronized int select (Object_Channel[] c) throws InterruptedException {
int selected;
int i;
state = ENABLING; // ALT START
for (i = 0; i < c.length; i++) {
if (c[i].enable(this)) { // ENABLE CHANNEL
state = READY;
break;
}
}
if (state == ENABLING) { // ALT WAIT
state = WAITING;
wait ();
}
// assert : state == READY
selected = i;
for (i--; i >= 0; i--) {
if (c[i].disable()) { // DISABLE CHANNEL
selected = i;
}
}
state = INACTIVE;
return selected; // ALT END
}
// (PRI) ALT on a (condition & channel array)
public synchronized int select (Object_Channel[] c, boolean[] guard) throws InterruptedException {
int selected;
int i;
state = ENABLING; // ALT START
for (i = 0; i < c.length; i++) {
if (guard[i] && c[i].enable(this)) { // ENABLE CHANNEL
state = READY;
break;
}
}
if (state == ENABLING) { // ALT WAIT
state = WAITING;
wait ();
}
// assert : state == READY
selected = i;
for (i--; i >= 0; i--) {
if (guard[i] && c[i].disable()) { // DISABLE CHANNEL
selected = i;
}
}
state = INACTIVE;
return selected; // ALT END
}
// (PRI) ALT on a channel array and a timeout
public synchronized int select (Object_Channel[] c, long msecs) throws InterruptedException {
int selected;
int i;
state = ENABLING; // ALT START
for (i = 0; i < c.length; i++) {
if (c[i].enable(this)) { // ENABLE CHANNEL
state = READY;
break;
}
}
if (state == ENABLING) { // ALT WAIT
state = WAITING;
if (msecs > 0) wait (msecs);
state = READY; // in case we timed out ...
}
// assert : state == READY
selected = i;
for (i--; i >= 0; i--) {
if (c[i].disable()) { // DISABLE CHANNEL
selected = i;
}
}
state = INACTIVE;
return selected; // ALT END
}
public synchronized int select (Object_Channel[] c, long msecs, int nsecs) throws InterruptedException {
int selected;
int i;
state = ENABLING; // ALT START
for (i = 0; i < c.length; i++) {
if (c[i].enable(this)) { // ENABLE CHANNEL
state = READY;
break;
}
}
if (state == ENABLING) { // ALT WAIT
state = WAITING;
if (msecs > 0) wait (msecs, nsecs);
state = READY; // in case we timed out ...
}
// assert : state == READY
selected = i;
for (i--; i >= 0; i--) {
if (c[i].disable()) { // DISABLE CHANNEL
selected = i;
}
}
state = INACTIVE;
return selected; // ALT END
}
// (PRI) ALT on a (condition & channel array) and (condition & timeout)
public synchronized int select (Object_Channel[] c, boolean[] guard,
long msecs, boolean t_guard)
throws InterruptedException {
int selected;
int i;
state = ENABLING; // ALT START
for (i = 0; i < c.length; i++) {
if (guard[i] && c[i].enable(this)) { // ENABLE CHANNEL
state = READY;
break;
}
}
if (state == ENABLING) { // ALT WAIT
state = WAITING;
if (t_guard) {
if (msecs > 0) wait (msecs);
state = READY; // in case we timed out ...
} else {
wait ();
}
}
// assert : state == READY
selected = i;
for (i--; i >= 0; i--) {
if (guard[i] && c[i].disable()) { // DISABLE CHANNEL
selected = i;
}
}
state = INACTIVE;
return selected; // ALT END
}
public synchronized int select (Object_Channel[] c, boolean[] guard,
long msecs, int nsecs, boolean t_guard)
throws InterruptedException {
int selected;
int i;
state = ENABLING; // ALT START
for (i = 0; i < c.length; i++) {
if (guard[i] && c[i].enable(this)) { // ENABLE CHANNEL
state = READY;
break;
}
}
if (state == ENABLING) { // ALT WAIT
state = WAITING;
if (t_guard) {
if (msecs > 0) wait (msecs, nsecs);
state = READY; // in case we timed out ...
} else {
wait ();
}
}
// assert : state == READY
selected = i;
for (i--; i >= 0; i--) {
if (guard[i] && c[i].disable()) { // DISABLE CHANNEL
selected = i;
}
}
state = INACTIVE;
return selected; // ALT END
}
// (PRI) ALT on a channel array and (condition & SKIP)
public int select (Object_Channel[] c, boolean skip) throws InterruptedException {
if (skip) {
int i;
for (i = 0; i < c.length; i++) {
if (! c[i].channel_empty) {
break;
}
}
return i;
} else {
return select (c);
}
}
// (PRI) ALT on a (condition & channel array) and (condition & SKIP)
public int select (Object_Channel[] c, boolean[] guard, boolean skip) throws InterruptedException {
if (skip) {
int i;
for (i = 0; i < c.length; i++) {
if (guard[i] && (! c[i].channel_empty)) {
break;
}
}
return i;
} else {
return select (c, guard);
}
}
synchronized void schedule () {
if (state == WAITING) {
state = READY;
notify ();
}
}
}