/* 
 * ReaderWriterMon.java (Implements Readers/Writers Using Semaphores).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 * 
 * Portions copyright(c) 2000 to School of Electrical Engineering and 
 * Computer Science, UCF, Orlando.                   
 *
 * Use and distribution of this source code are strictly governed by 
 * terms and conditions set by the authors.
 * 
 * $Id : ReaderWriterMon.java, v1.0.0 02/07/2001. $
 *
 * Revision History Revisited:
 *
 */

import java.util.*;
import java.lang.*;

/* Start of ReaderWriterMon.*/
public class ReaderWriterMon{
     int nNumberOfWriters;              /* Tracks # of Writers.*/
     int nNumberOfReaders;              /* Tracks # of Readers.*/
     boolean bEndCondition;             /* End Condition for it.*/
     int nEvents;                       /* Basically # of writes.*/
     long lStartTime,lStopTime;         /* Timers used to print messages
                                           during simulation.*/
     int nReaderCount;                  /* Number of readers currently
                                           in the critical section.*/
     int nReads;                        /* # of current reads.*/
     int nWrites;                       /* # of current writes.*/
     int nTok;                          /* current token number.*/
     int nInsRead;                      /* # of readers read.*/

     /* Synchronization Mechanism.*/
     Semaphore Mutex;                   /* This is basically used to
                                           protect the counter.*/
     Semaphore DB;                      /* Used to protect database.*/
     Semaphore Block;                   /* Block piece of code.*/
     Semaphore WBlock;                  /* Same here.*/
     Semaphore RBlock;                  /* Same here.*/

     ReaderWriterWMon Writer[];      /* Array of Writers.*/
     ReaderWriterRMon Reader[];      /* Array of Readers.*/

     
     /* 
      * This function is constructor for this class.
      */
     public ReaderWriterMon( int nNumberOfWriter,
                             int nNumberOfReader,
                             int nEvents,
                             long lStartTime){

       /* Store them within this P/C controller.*/
       this.nNumberOfWriters = nNumberOfWriter;
       this.nNumberOfReaders = nNumberOfReader;
       this.nEvents           = nEvents;  
       this.lStartTime        = lStartTime;   

       /* Initialise Synchronization Mechanism.*/
       Mutex   = new Semaphore(1);
       DB      = new Semaphore(1); 
       Block   = new Semaphore(1);
       WBlock  = new Semaphore(1);
       RBlock  = new Semaphore(1);

       nReaderCount = 0;
       nReads     = 0;
       nWrites    = 0;
       nTok       = 0;
       nInsRead   = nNumberOfReaders;
     }/* End of BoundedBufferSem.*/

     /*
      * This program is heart of this                            
      */
      public void Start(){
        /* Create all the producers and consumers.*/
        Writer = new ReaderWriterWMon[nNumberOfWriters];
        Reader = new ReaderWriterRMon[nNumberOfReaders];

        /* Print the Start Time.*/
        long lInterStartTime = System.currentTimeMillis();
        TimeFormat Time = new TimeFormat();
        System.out.println("Started using Monitors at time " + 
                           Time.formatTime(lInterStartTime - lStartTime));

        /* Initialise their Environment.*/
        for(int nIndex=0; nIndex < nNumberOfWriters; nIndex++){
         Writer[nIndex] = new ReaderWriterWMon(nIndex+1,this);
         Writer[nIndex].start();
        }/* End for.*/

        for(int nIndex=0; nIndex < nNumberOfReaders; nIndex++){
         Reader[nIndex] = new ReaderWriterRMon(nIndex+1,this);
         Reader[nIndex].start();
        }/* End For.*/


        boolean bAllDead = false;
        while(bAllDead == false){
         bAllDead = true;
         for(int nIndex=0; nIndex < nNumberOfWriters; nIndex++){
          if(Writer[nIndex].isAlive() == true){ 
           bAllDead = false;
           break;
          }/* End if.*/
         }/* End for.*/

         for(int nIndex=0; nIndex < nNumberOfReaders; nIndex++){
          if(Reader[nIndex].isAlive() == true){ 
           bAllDead = false;
           break;
          }/* End if.*/
         }/* End for.*/
        }/* End While.*/

        lStopTime = System.currentTimeMillis();
        System.out.println("Completed using Monitors at time " + 
                           Time.formatTime(lStopTime - lStartTime));
       }/* End of Start.*/

       /*
        * Locks Everything to read in the database.
        */
        int StartRead(int nMyToken, ReaderWriterRMon rThis){

          Block.P(); /* Block this section of code using semaphores.*/
          if(nReads == nEvents*nNumberOfReaders){
           rThis.SetEndCondition(false);
           Block.V();
           return -1;
          }/* End if.*/

          RBlock.P();
          if(nMyToken == nTok){
          /* Means he has already this value, so don't allow him
             to read the value again.*/
             RBlock.V();
             Block.V();
             return -1;
          }/* End if.*/
          rThis.nToken = nTok;
          RBlock.V();

          Mutex.P();     /* Acquire Lock for Incrementing reader count.*/
          nReaderCount++;
          if(nReaderCount == 1) DB.P();
          Mutex.V();     /* Release Lock.*/
          return 1;
        }/* End StartRead.*/

        /*
         * Ends the Reading of Database.
         */
         void EndRead(){
           Mutex.P();
           nReaderCount--;
           if(nReaderCount == 0) DB.V();
           Mutex.V();
           Block.V();
         }/* End of EndRead.*/

         /*
          * Reads the database and each reader reads a write value only
          * once.
          */
          void ReadDatabase(ReaderWriterRMon rThis){

           /* SIMULATE READ DATABASE HERE.*/

           RBlock.P();
           nInsRead++;
           nReads++;
           RBlock.V();
          }/* End of ReadDatabase.*/

          /*
           * Starts Writing of database.
           */
           int StartWrite(ReaderWriterWMon wThis){
             WBlock.P();

             if(nWrites == nEvents){ 
              wThis.SetEndCondition(false);
              WBlock.V();
              return -1;
             }/* End if.*/

             RBlock.P();
             if(nInsRead != nNumberOfReaders){
              RBlock.V();
              WBlock.V();
              return -1;
             }else{
              nInsRead = 0;
             }/* End if.*/

             RBlock.V();
          
             /* SIMULATE CREATE DATABASE RECORD.*/

             DB.P();
             return 1;
           }/* End of StartWrite.*/

           /*
            * Ends Write.
            */
            void EndWrite(){
              DB.V();
              WBlock.V();
            }/* End of EndWrite.*/

            /*
             * Writes the values to the database.
             */
        void WriteDatabase(ReaderWriterWMon wThis){

          /* SIMULATE WRITE RECORD TO DATABASE.*/
          nTok++;

          nWrites++;
        }/* End of WriteDatabase.*/

}/* End of ReaderWriterMon.*/

