//{{{}}} // package occam; //{{{ public class Alternative { public class Alternative { //{{{ COMMENT 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. // //{{{ (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. // //}}} // //{{{ (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. // //}}} // //{{{ (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). // //}}} //{{{ state private static final int inactive = 0; // whatever happened to private static final int enabling = 1; // enumerated types? private static final int waiting = 2; private static final int ready = 3; private int state = inactive; //}}} //{{{ (PRI) ALT on a channel array public synchronized int select (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 (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 (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 (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 (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 (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 (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 (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 () { synchronized void schedule () { if (state == waiting) { state = ready; notify (); } } //}}} } //}}}