//
// $Source: /home/cur/djb1/java/threads/RCS/CHAN_OF_INT.java,v $
//
// $Id: CHAN_OF_INT.java,v 1.1 1996/10/02 15:19:28 djb1 Exp $
//
// CHAN_OF_INT class - an occam CHAN OF INT for multiple readers and writers.
//
// (C) Copyright 1996 Peter Welch <P.H.Welch@ukc.ac.uk> and
//                    Dave Beckett <D.J.Beckett@ukc.ac.uk>
// University of Kent at Canterbury
//

import java.lang.InterruptedException;

//{{{  description (javadoc format)
/**
 * Channel extends an occam CHAN OF INT for multiple readers and writers.
 *
 * There is full synchronisation between a reading and writing thread.  Any
 * thread may read or write on this channel.  Readers and writers are queued
 * separately.  A reader only completes when it gets to the front of its queue
 * and finds a writer.  A writer only completes when it gets to the front of
 * its queue and finds a reader.
 *<p>
 * There is no logical buffering of data in the channel however each int
 * is actually copied three times with this implementation.
 *
 *@version $Revision: 1.1 $
 *@author  Peter Welch, P.H.Welch@ukc.ac.uk
 *@author  Dave Beckett, D.J.Beckett@ukc.ac.uk
 */
//}}}  

class CHAN_OF_INT {
  //{{{  private member data
  private int channel_hold;             // buffer (not detectable to users)
  
  private boolean channel_empty = true; // synchronisation flag
  
  Object read_monitor =                 // all readers multiplex through this
    new Object ();
  
  Object write_monitor =                // all writers multiplex through this
    new Object ();
  
  //}}}  
  //{{{  read method
  /**
   *  <tt>read</tt> method: read an int from the channel. This method
   *  blocks until a corresponding thread calls the write method,
   *  at which point a rendezvous is formed and the data is passed.
   *
   *@return  the object sent from the writing thread.
   *
   *@exception InterruptedException
   *           Occurs if the wait methods are interrupted.
   */
  public int read () throws InterruptedException {
    synchronized (read_monitor) {
      synchronized (this) {
        if (channel_empty) {
          channel_empty = false;           // first to the rendezvous
          wait ();                         // wait for the writer thread
          notify ();                       // schedule the writer to finish
        } else {
          channel_empty = true;            // second to the rendezvous
          notify ();                       // schedule the waiting writer thread
        }
        return channel_hold;
      }
    }
  }
  
  //}}}  
  //{{{  write method
  /**
   *  <tt>write</tt> method: write an int to the channel. This method
   *  blocks until a corresponding thread calls the read method,
   *  at which point a rendezvous is formed and the data is passed.
   *
   *@param  n  the int to be sent to the reading thread.
   *
   *@exception InterruptedException
   *           Occurs if the wait methods are interrupted.
   */

  public void write (int n) throws InterruptedException {
   synchronized (write_monitor) {
     synchronized (this) {
        channel_hold = n;
        if (channel_empty) {
          channel_empty = false;           // first to the rendezvous
          wait ();                         // wait for the reader thread
        } else {
          channel_empty = true;            // second to the rendezvous
          notify ();                       // schedule the waiting reader thread
          wait ();                         // let the reader regain this monitor
        }
      }
    }
  }
  
  //}}}  
  //{{{  is_empty method
  /**
   *  <tt>is_empty</tt> method: determine whether a thread is waiting at the
   *  other end of the channel. This can be used either at the writing or the
   *  reading end of the channel.
   *
   *@return  true iff no thread is waiting at the other end.
   */

  public boolean is_empty () 
  {
    return channel_empty;
  }
  
  //}}}  
}
