// boundedbuf.cc
// This is a simple bounded buffer of ints intended to be used as a
// communication channel between threads.  See boundedbuf.h for more
// info.  Some of the procedures have been left for you to implement.
// -Max Hailperin <max@gac.edu> 9/23/96

#include "boundedbuf.h"

BBuf::BBuf(){
  count = 0; // no data
  nextRead = nextWrite = 0; // start at buf[0]
  shut = 0; // not shutdown yet
  lock = new Lock("monitor lock for bounded buffer");
  data = new Condition("condition variable for data availability in BBuf");
  space = new Condition("condition variable for space availability in BBuf");
}

//----------------------------------------------------------------------
//put
// This puts a single int into the buffer, which must not have been
// shutdown yet.  This may involve sleeping until there is space, and
// may involve waking up a consumer who was sleeping awaiting data.
//----------------------------------------------------------------------

void BBuf::put(int n){
  lock->Acquire();
  while(count == size && !shut){
    space->Wait(lock);
  }
  ASSERT(!shut);
  if(count++ == 0)
    data->Signal(lock);
  buf[nextWrite++] = n;
  if(nextWrite == size){
    nextWrite = 0; // wrap around
  }
  lock->Release();
}

//----------------------------------------------------------------------
//shutdown
// This "shuts down" the buffer, which must not have been shutdown
// yet.  This should wake up *all* consumers who were sleeping awaiting
// data, since unlike a data value put with put, there is no problem with
// them all discovering that no more data is coming (and you don't want
// them to sleep forever).  You should also wake up *all* producers waiting
// for space, so they can discover their error situation of trying to
// put into a shutdown buffer.  You need to write this procedure.
//----------------------------------------------------------------------
void BBuf::shutdown(){
}

//----------------------------------------------------------------------
//get
// This gets a single int from the buffer, unless it has been shutdown
// and there is no buffered data remaining.  (Note that even if the
// buffer was shutdown, if there is data it should be returned -- we
// "drain" all the buffered data out.)  If a value is gotten, it will
// be stored into the reference argument, n, and 1 returned.  If none is
// gotten, because the buffer is empty and shutdown, then 0 will be returned
// (and n is unchanged).  If there is no buffered data, but the buffer
// isn't shut down yet, then get must sleep until there is data or the
// buffer has been shutdown.  Once a value is gotten, it may be necessary
// to wake up a sleeping producer that was waiting for space.  This is
// another procedure you need to write.
//----------------------------------------------------------------------
int BBuf::get(int& n){
}