package edu.vt.marian.common;


/** 
        This class provides a moniter object for thread coordination.
                It supports multiple readers/single writer mode.

        uses the services of class(es):
                ReaderWriterMutex(Debug debug)
                ReaderWriterMutex(int reader_limit, Debug debug)
                void read_enter()
                void read_exit()
                void writer_enter()
                void writer_exit()
                int get_max_active_reader_number()
                int set_max_active_reader_number(int reader_limit)

        designer(s): Jianxin Zhao (jxzhao@csgrad.cs.vt.edu)
        implementator(s): Pingang Wang (pwang@csgrad.cs.vt.edu)
        finished time: 11/23/98
        known bugs: None
        JDK version: JDK 1.1.5
        side effects: Unknown
*/
public class ReaderWriterMutex 
{
        // this variable stores current number of active readers
        private int active_reader_number;

        // this variable stores the limit of active readers
        private int max_active_reader_number;

        // this flag indicates if there's an active writer in the critical region
        private boolean writer_active;

        // this flag indicates if there're some writer waiting to enter the critical region
        private boolean writer_waiting;

        // debug object
        private Debug debug;

/**
        method name: ReaderWriterMutex
        method description: constructor of ReaderWriterMutex class
        uses the services of class(es):
        input parameter(s):
                Debug - debug object
        output parameter(s): none
        return value: none
        synchronization consideration: 
*/
        public ReaderWriterMutex(Debug debug)
        {
                this.debug = debug;

                // set max active reader to default value
                max_active_reader_number = 0x7fffffff;  // MAX_INTEGER

                // initialize flags
                active_reader_number = 0;
                writer_active = false;
                writer_waiting = false;
        }

/**
        method name: ReaderWriterMutex
        method description: constructor of ReaderWriterMutex class
        uses the services of class(es):
        input parameter(s):
                int reader_limit - cocurrent reader limit
                Debug debug - debug object
        output parameter(s): none
        return value: none
        synchronization consideration: 
*/
        public ReaderWriterMutex(int reader_limit, Debug debug)
        {
                this.debug = debug;

                // check if the limit is in proper range (>0)
                if (reader_limit > 0)
                {
                        max_active_reader_number = reader_limit;
                }
                else
                {
                        debug.dumpTrace("negative reader_limit identified");
                        max_active_reader_number = 0x7fffffff;  // MAX_INTEGER
                }

                active_reader_number = 0;
                writer_active = false;
                writer_waiting = false;
        }


/**
        method name: reader_enter
        method description: This method is called when a reader enters the critical section.
        uses the services of class(es):
        input parameter(s): none
        output parameter(s): none
        return value: none
        synchronization consideration: 
*/
        public synchronized void reader_enter()
        {
                // the reader will be put into the waiting queue in any of these cases:
                // 1. there's an active writer
                // 2. there're writers waiting to enter the critical region
                // 3. maximum active reader limit is reached
                while (writer_active || writer_waiting || (active_reader_number >= max_active_reader_number)) 
                {
                        try
                        {
                                wait();
                        }
                        catch (InterruptedException e)
                        {
                                debug.dumpTrace("exception caught in method reader_enter wait()");
                        }
                }

                // reader gets permit to enter the critical region
                active_reader_number ++;
        }

/**
        method name: reader_exit
        method description: This method is called when a reader exits the critical section.
        uses the services of class(es):
        input parameter(s): none
        output parameter(s): none
        return value: none
        synchronization consideration: 
*/
        public synchronized void reader_exit() 
        {
                // check for error: no writer & reader can enter simultaneously
                if (writer_active)
                {
                        debug.dumpTrace("Error 2: Writer active while reader exit");
                        return;
                }

                // check if there's error in counting active reader
                if (active_reader_number == 0)
                {
                        debug.dumpTrace("Error 3: Reader number < 0");
                        return;
                }

                // reduce the number of activer reader
                active_reader_number --;

                // wake up all waiting threads
                notifyAll();
        }

/**
        method name: writer_enter
        method description: This method is called when a writer enters the critical section.
        uses the services of class(es):
        input parameter(s): none
        output parameter(s): none
        return value: none
        synchronization consideration: 
*/
        public synchronized void writer_enter()
        {
                // the writer will be paused if there're active readers or writer
                while ((active_reader_number > 0) || writer_active) 
                {
                        // if there're active readers, set writer waiting flag
                        if (active_reader_number > 0) 
                        {
                                writer_waiting = true;
                        }

                        try
                        {
                                wait();
                        }
                        catch (InterruptedException e)
                        {
                                debug.dumpTrace("exception caught in method writer_enter wait()");
                        }
                }

                // set writer status flags
                writer_waiting = false;         // it might not be
                writer_active = true;
        }

/**
        method name: writer_exit
        method description: This method is called when a writer exits the critical section.
        uses the services of class(es):
        input parameter(s): none
        output parameter(s): none
        return value: none
        synchronization consideration:
*/
        public synchronized void writer_exit()
        {
                // check for error: no writer & reader can enter simultaneously
                if (active_reader_number != 0)
                {
                        debug.dumpTrace("Error 4: reader entered before writer exit");
                }

                // check if writer active flag is correctly set
                if (writer_active == false)
                {
                        debug.dumpTrace("Error 5: Wrong Write Active flag");
                }

                // clear writer active flag
                writer_active = false;

                // wake up all waiting threads
                notifyAll();
        }

/**
        method name: get_max_active_reader_number
        method description: Return the limit of active readers.
        uses the services of class(es):
        input parameter(s): none
        output parameter(s): none
        return value: limit of active readers
        synchronization consideration: 
*/
        public int get_max_active_reader_number()
        {
                return max_active_reader_number;
        }

/**
        method name: get_max_active_reader_number
        method description: Set the limit of active readers.
        uses the services of class(es):
        input parameter(s):
                int reader_limit - active reader limit
        output parameter(s): none
        return value: none
        synchronization consideration: 
*/
        public int set_max_active_reader_number(int reader_limit)
        {
                final int SUCCESS = 0;
                final int FAIL = -1;

                if (reader_limit <= 0)
                {
                        debug.dumpTrace("negative reader_limit identified");
                        return FAIL;
                }

                max_active_reader_number = reader_limit;
                return SUCCESS;
        }

}
