//Editor-Info: -*- C++ -*-
//
//Subject: Scheduler Framework
//
//File: fifoscheduler.h
//
//Version: $Revision: 1.8 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/10/01 08:19:07 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Juhana Räsänen
//
//Description:
//      A scheduler class for Scheduler Framework that is capable
//      of conduit scheduling and OmniBroker ORB Reactor dispatch.
//      Requires OmniBroker v1.0 or higher (http://www.ooc.com/)
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 
//

#ifndef __SF_FIFOSCHEDULER_H__
#define __SF_FIFOSCHEDULER_H__

#define ORB_USED

#include <typeinfo>
#include <string>
#include <list>
#ifdef ORB_USED
#include <OB/CORBA.h>
#include <OB/Util.h>
#include <OB/Basic.h>
#include <OB/Reactor.h>
#endif
#include <sys/types.h>
#include "scheduler.h"
#include "schedulerhandle.h"
#include "otime.h"

//
// Class: sfFIFOScheduler
//
// Description:
//     Implements a simple FIFO scheduler for SF task scheduling.
//     Tasks are served in the order they request CPU, along with the
//     timeout and asynchronous I/O requests. No priority or load of
//     the tasks is taken into account.
//     The only scheduler parameter that can be adjusted is the maximum
//     number of tasks that can be run subsequently before timeouts and
//     file descriptors are examined again; this value is a trade-off
//     between timeout accuracy and overall scheduler performance. If
//     the tasks execute quickly, the value can be increased.
//
// Description:
//     Implements a FIFO scheduler that acts at the same time as a
//     reactor for OmniBroker ORB. Using this scheduler it is possible
//     to combine CORBA objects and SF tasks into same application. It
//     is necessary to do it inside a single class, because both CORBA
//     and SF use select() system call to do asynchronous I/O. Apart
//     from inclusion of ORB Reactor, this sheduler is a very simple
//     one implementing same scheduling policy as sfFIFOScheduler.
//     Tasks are served in the order they request CPU, along with the
//     timeout and asynchronous I/O requests. No priority or load of
//     the tasks is taken into account.
//     The only scheduler parameter that can be adjusted is the maximum
//     number of tasks that can be run subsequently before timeouts and
//     file descriptors are examined again; this value is a trade-off
//     between timeout accuracy and overall scheduler performance. If
//     the tasks execute quickly, the value can be increased.
//

class sfFIFOScheduler : public sfScheduler
{
    private:
//
// Class: sfFIFOScheduler::FIFOHandle
//
// Description:
//     An internal class of the FIFO scheduler to take care of the tasks'
//     interface to the scheduler. An instance of FIFOHandle should be
//     bound to each sfTask that is to be scheduled by sfFIFOScheduler.
//     The handle is capable of adding itself to the scheduler queues
//     as well as removing itself from the queues.
//
// Description: 
//     An internal class of the ORB scheduler to take care of the tasks'
//     interface to the scheduler. An instance of FIFOHandle should be
//     bound to each sfTask that is to be scheduled by sfORBScheduler.
//     The handle is capable of adding itself to the scheduler queues
//     as well as removing itself from the queues.
//     ORBHandle is inherited from OBEventHandler, because the select
//     operation is done inside code derived from OmniBroker.
//

        class FIFOHandle : public sfSchedulerHandle
#ifdef ORB_USED
		         , public OBEventHandler
#endif
        {
            public:
                friend class sfFIFOScheduler;
                static const int MAX_TIMEOUTS = 1;
                static const int MAX_READS = 1;
                static const int MAX_WRITES = 1;

                virtual ~FIFOHandle(void);

                virtual void scheduleTask(void);
                virtual void scheduleTimeout(const OTime &timeout_);
                virtual void scheduleAbsoluteTimeout(const OTime &timeout_);
                virtual void scheduleRead(int fileDescriptor_,
                                          const OTime &timeout_);
                virtual void scheduleWrite(int fileDescriptor_,
                                           const OTime &timeout_);

                virtual void removeTask(void);
                virtual void unscheduleTask(void);
                virtual void unscheduleTimeout(void);
                virtual void unscheduleRead(void);
                virtual void unscheduleWrite(void);

#ifdef ORB_USED
                virtual void handleEvent(OBMask mask_);
                virtual void handleStop(void);
#endif

                void link(FIFOHandle *handle_);
                FIFOHandle *unlink(void);

            protected:
                FIFOHandle(void);
                FIFOHandle(sfFIFOScheduler *scheduler_, sfTask *task_);

            private:
                sfFIFOScheduler *_scheduler;

                int _pendingCPUReqs;  // Number of pending CPU requests
                int _pendingTimeouts; // Number of pending timeouts
                int _pendingReads;    // Number of pending read requests
                int _pendingWrites;   // Number of pending write requests

                OTime _timeout;       // Timeout value
                int _readFD;          // File descriptor for reading
                int _writeFD;         // File descriptor for writing

                // A list structure is included in the FIFOHandle for
                // performance reasons; this list is used only for
                // the CPU requests queue, others are implemented as
                // STL lists in the scheduler.
                FIFOHandle *_prevTask;
                FIFOHandle *_nextTask;
        };


    public:
        friend class sfFIFOScheduler::FIFOHandle;

        // Methods for sfScheduler functionality
        static sfFIFOScheduler* instance();
        virtual ~sfFIFOScheduler(void);
        virtual void step(void);
        virtual sfSchedulerHandle *makeHandle(sfTask *task_);

#ifdef ORB_USED
        static void initORB(int argc_, char* argv_[]);
        static CORBA_ORB_ptr getORB(void);
        static CORBA_BOA_ptr getBOA(void);
#endif

    protected:
        static const int MAX_TASKS_AT_ONE_PASS = 5;
        static const int MAX_TIMEOUTS_AT_ONE_PASS = 10;
        sfFIFOScheduler(int taskCount_ = MAX_TASKS_AT_ONE_PASS,
                        int timeoutCount_ = MAX_TIMEOUTS_AT_ONE_PASS);

    private:
        void synchronize(void);
#ifndef ORB_USED
        int create_fd_sets(void);
        void handle_fd_sets(void);
#endif
        int fifoQueueEmpty(void) const;

        int _taskCount;
        int _timeoutCount;
        OTime _localTime;

        FIFOHandle *_fifoQueue; // Runnable queue

        typedef list<FIFOHandle *> taskHandleList;
        typedef taskHandleList::iterator taskHandleIterator;
        taskHandleList _timeoutList;
        taskHandleList _readList;
        taskHandleList _writeList;

        struct fd_set _read_fds;
        struct fd_set _write_fds;

        int _selectFlag; // Indicates that there are pending timeouts
                         // or file operations (when _selectFlag != 0)
#ifdef ORB_USED
        OBReactor *_reactor;
        static CORBA_ORB_var _orb;
        static CORBA_BOA_var _boa;
#endif
        static sfFIFOScheduler *_only;
};

#endif // __SF_FIFOSCHEDULER_H__

