#if   !defined(__SEMAPHORECOMMON_HPP)
#define __SEMAPHORECOMMON_HPP

/*
  CoreLinux++ 
  Copyright (C) 1999,2000 CoreLinux Consortium
  
   The CoreLinux++ Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CoreLinux++ Library Library is distributed in the hope that it will 
   be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  
*/

#if !defined(__COMMON_HPP)
#include <Common.hpp>
#endif

namespace corelinux
{
   /**
      Describes the tip control block for the Common Storage Area (CSA)
   */

   struct   _CSAHeader
   {
      Int      creatorId;        // 0 if not opened before
      Int      currentUsed;      // The current used up in the pool
      Int      currentGrps;      // The current groups present
      Int      reserved;         // 
   };

   DECLARE_TYPE( struct _CSAHeader, CSAHeader );

   /**
      Describes a CSA semaphore group
   */

   struct   _CSAGroupHeader
   {
      Int   groupInfo;           // Either an Id, 0 if tail, or -1 if available
      Int   groupShares;         // How many processes are using this
      Int   groupType;           // -1 not used, 0 Mutex, 1 Gateway, 2-10 res
      Int   groupSemCount;       // Semaphore count if info is -1 
      // and not reclaimed | !0 
   };

   DECLARE_TYPE( struct _CSAGroupHeader, CSAGrpHeader );

   /**
      Describes a CSA semaphore entry
   */

   struct   _CSASemaphoreHeader
   {
      Int   semOwner;            // Current semaphore owner
      Int   maxSemValue;         // 1 for mutexes, n for others, -1 if control
      Word  isRecursive;         // ? for instance, 0 for control
      Word  isBalking;           // ? for instance, 0 for control
      Int   semShares;           // Shares for this semaphore
   };

   DECLARE_TYPE( struct _CSASemaphoreHeader, CSASemHeader );

   DECLARE_CLASS( CoreLinuxGuardPool );

   DECLARE_CLASS( SemaphoreGroup );

   DECLARE_CLASS( MemoryStorage );
 
   DECLARE_CLASS( SemaphoreCommon );

   /**
      The SemaphoreCommon manages the SemaphoreGroup common storage
      area. This area is to communicate between address spaces when
      using one of the CoreLinux++ SemaphoreGroup types in public
      mode.
   */
   
   class SemaphoreCommon : public Synchronized
   {
   public:

      //
      // Accessors
      //

      /**
         Returns the maximum value for a semaphore as defined
         by the original semaphore claimant
         @param SemaphoreGroup pointer to group owner
         @param Int zero offset semaphore identifier
         @return Int -1 for local unknown, > 0 for common
      */
      static   Int   getSemaphoreMaxValue( SemaphoreGroupPtr, Int );

      //
      // Mutators
      //
      /**
         When a shared semaphore group is created, it
         is updated in the CSA, either by increasing
         the count of processes accessing a particular
         group, or adding to the csa initially
         @param SemaphoreGroup pointer
      */

      static   void  groupDefined( SemaphoreGroupPtr );

      /**
         When the local process is deleting a semaphore group
         and it is considered a shared group, we are asked
         to adjust the map accordingly.
         @param SemaphoreGroup pointer to the group
         @return Int number of shares on group
      */

      static   Int   groupUnDefined( SemaphoreGroupPtr );

      /**
         Called by the base semaphore to aquire a lock for a 
         specific semaphore.
         @param SemaphoreGroup pointer to the group
         @param Int the system group id
         @param Int the zero offset semaphore id
         @param Int the system dependent flag
         @return Int return code
      */

      static   Int   setLock( SemaphoreGroupPtr, Int, Int, Int );

      /**
         Called by the base semaphore to relinquish a lock for a 
         specific semaphore.
         @param SemaphoreGroup pointer to the group
         @param Int the system group id
         @param Int the zero offset semaphore id
         @param Int the system dependent flag
         @return Int return code
      */

      static   Int   setUnLock( SemaphoreGroupPtr, Int, Int, Int );

      /**
         Called by the base semaphore to wait for a 
         specific semaphore to have a zero value.
         @param SemaphoreGroup pointer to the group
         @param Int the system group id
         @param Int the zero offset semaphore id
         @param Int the system dependent flag
         @return Int return code
      */

      static   Int   waitZero( SemaphoreGroupPtr, Int, Int, Int );

      /**
         Typically called by a SemaphoreGroup prior to passing
         out the semaphore type to the caller.
         @param SemaphoreGroup the group pointer
         @param Int the semaphore identifier/index -1 = any
         @param Int reference the initial value (becomes the max if new)
         @param Int reference the recursive condition
         @param Int reference the balking condition
         @param Int 0 must not exist, 1 share, 2 must exist
      */
               
      static   Int   obtainSemaphore
         (
            SemaphoreGroupPtr,
            Int,
            IntRef,
            IntRef,
            IntRef,
            Int
         );
               
      /**
         Called when the semaphore is no longer being
         referenced. Effectively reducing the share
         count for shared group semaphores
         @param SemaphoreGroup pointer
         @param Int the zero index semaphore identifier
         @return Int the number of outstanding shares
      */

      static   Int   relinquishSemaphore(SemaphoreGroupPtr,Int);

      /**
         Called to set the semaphore maximum value. For
         local this is SETVAL, for shared it is ignored
         @param SemaphoreGroup pointer
         @param Int the zero index semaphore identifier
         @param Int the value
      */
               
      static   Int   setMaxValue( SemaphoreGroupPtr, Int, Int );



   protected:

    /// Default constructor used by class

    SemaphoreCommon( void );

    /// Destructor

    virtual           ~SemaphoreCommon( void );

    //
    // Instance mutators
    //

    /**
       Does the work of getting the group registered in 
       the CSA
       @param SemaphoreGroup pointer to register
    */

    void  registerGroup( SemaphoreGroupPtr );

    /**
       Does the work of reducing the group share count,
       or marking the group for reclaimation
       @param SemaphoreGroup pointer to register
    */

    Int   deregisterGroup( SemaphoreGroupPtr );

    /**
       Called when the group is determined to be shared and
       a semaphore share is to be claimed.
       @param SemaphoreGroup the group pointer
       @param Int the semaphore identifier/index -1 = any
       @param Int the initial value (becomes the max if new)
       @param IntRef  the recursive condition
       @param IntRef  the balking condition
       @param Int 0 must not exist, 1 share, 2 must exist
    */
               
    Int   claimSemaphore
    (
     SemaphoreGroupPtr,
     Int,
     IntRef,
     IntRef,
     IntRef,
     Int
     );

    /**
       Called when a group wishes to let the CSA reclaim
       a semaphore share.
       @param SemaphoreGroup the group pointer
       @param Int the semaphore identifier/index 
       @return Int the number of shares outstanding
    */

    Int   reclaimSemaphore(SemaphoreGroupPtr,Int);


    /// Attempt to locate a specific group

    CSAGrpHeaderPtr   findGroup
    ( 
     IntCref , 
     IntCref , 
     CSAGrpHeaderPtr 
     );

    /// Find open slot that fits count criteria

    CSAGrpHeaderPtr   findAvailableGroup
    ( 
     IntCref , 
     IntCref , 
     CSAGrpHeaderPtr 
     );

    /// Utility to clean CSA group tail

    CSAGrpHeaderPtr   subsetGroup( Int, CSAGrpHeaderPtr ) ;

    CSAGrpHeaderPtr   combineGroup( Int, CSAGrpHeaderPtr ) ;

    bool  isOriginator( void ) const;

    Int   getOriginatorId( void ) const;

    Int   canonicalUndefined( void );


    /// Factory for CSA

    static   void  createAttachment( void );

    friend   class CoreLinuxGuardPool;

    /// On the way out from run-time

    static   void  exitAttachment( void );


  private:

    SemaphoreCommon( SemaphoreCommonCref )
      throw ( Assertion )
      :
      Synchronized()
    {
      NEVER_GET_HERE;
    }

  private:

    MemoryStoragePtr     theCSA;
    CSAHeaderPtr         theBase;
    bool                 theOriginator;
    static   SemaphoreCommonPtr   theInstance;
    static   SemaphoreGroupPtr    theControlGroup;
    static   bool                 theInitializeFlag;
  };

}

#endif // if !defined(__SEMAPHORECOMMON_HPP)

/*
   Common rcs information do not modify
   $Author: dulimart $
   $Revision: 1.9 $
   $Date: 2000/09/09 07:06:17 $
   $Locker:  $
*/

