/*
  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

#if !defined(__SEMAPHORECOMMON_HPP)
#include <SemaphoreCommon.hpp>
#endif

#if   !defined(__MEMORY_HPP)
#include <Memory.hpp>
#endif

#if   !defined(__MEMORYSTORAGE_HPP)
#include <MemoryStorage.hpp>
#endif

#if   !defined(__MUTEXSEMAPHOREGROUP_HPP)
#include <MutexSemaphoreGroup.hpp>
#endif

extern "C"
{
   #include <stdio.h>
   #include <fcntl.h>
   #include <unistd.h>
   #include <sys/sem.h>
}

static   const char  *ourIdBase = "clsemcsa";
static   const char  *ourId = "/tmp/clsemcsa";
static   const char  *ourMemId = "clsemcsa.csa";
static   const Int   POOLSIZE(4096);
static   const Int   TOTALAVAILABLESLOTS(255);
static   const Int   TEMPBUFFSIZE(128);
static   const Short COMMONSEMCOUNT(1);   
static   const Int   ON(1);
static   const Int   OFF(0);
static   const Int   MUST_NOTEXIST(0);
static   const Int   MUST_SHARE(1);
static   const Int   MUST_EXIST(2);
static   const Int   SEMPHORE_UNAVAILABLE(-2);

namespace corelinux
{
   //
   // Macro for resolving the control semaphore
   //

   #define  GETCNTLSEM( aSem, aGrp, aOffset )   \
      (aSem) = (CSASemHeaderPtr)(aGrp);         \
      (aSem) += (aOffset)
      
   //
   // Lock control
   //

   #define  LOCKSEM( aGid, aId , aSem )                     \
      struct sembuf aSem ## sem_lock={ (aId)-1, -1, 0 };    \
      semop( (aGid), &aSem ## sem_lock,1);                  \
      (aSem)->semOwner = (Int) Thread::getThreadIdentifier()
   
   //
   // Unlock control
   //

   #define  UNLOCKSEM(aGid, aId, aSem )         \
      (aSem)->semOwner = 0;                       \
      struct sembuf aSem ## sem_unlock={ (aId)-1, 1, IPC_NOWAIT}; \
      semop( (aGid),&aSem ## sem_unlock,1)

   SemaphoreCommonPtr   SemaphoreCommon::theInstance( NULLPTR );
   SemaphoreGroupPtr    SemaphoreCommon::theControlGroup( NULLPTR );
   bool                 SemaphoreCommon::theInitializeFlag(false);

   //
   // Constructor
   //

   SemaphoreCommon::SemaphoreCommon( void )
      :
      Synchronized(),
      theCSA(NULLPTR),
      theBase(NULLPTR),
      theOriginator(false)
   {
      theInitializeFlag = true;

      //
      // If the csa doesn't exist yet for our address space,
      // we create it and do some discovery or setting
      //

      theCSA = Memory::createStorage
                  (
                     ourMemId,
                     POOLSIZE,
                     CREATE_OR_REUSE,
                     OWNER_ALL | GROUP_ALL | PUBLIC_ALL 
                  );

      // Map the relevant locations

      theBase = CSAHeaderPtr( *theCSA );

      //
      // Setup for control
      //

      CSAGrpHeaderPtr   aGrpPtr( (CSAGrpHeaderPtr)theBase );
      char              myTokenizer[TEMPBUFFSIZE];
      ThreadIdentifier  aId( Thread::getThreadIdentifier() );
      CSASemHeaderPtr   aSemPtr( NULLPTR );

      strcpy(myTokenizer,ourIdBase);
      ++aGrpPtr;

      //
      // If we are the founder
      //

      if( theBase->creatorId == 0 )
      {
         theBase->creatorId = (Int)aId;
         theBase->currentUsed = 0;
         theBase->currentGrps = 0;
         theOriginator = true;

         sprintf(&myTokenizer[strlen(myTokenizer)],".%d",theBase->creatorId);

         theControlGroup = new MutexSemaphoreGroup
            (
               COMMONSEMCOUNT,
               myTokenizer,
               OWNER_ALL|GROUP_ALL|PUBLIC_ALL,
               FAIL_IF_EXISTS
            );

         // Setup the group identifier

         SemaphoreGroupIdentifier   aGident(theControlGroup->getIdentifier());
         Int                        aGid( (Int) aGident );

         // First entry information

         theBase->currentGrps = 1;

         aGrpPtr->groupSemCount = theBase->currentUsed  = 
            theControlGroup->getSemaphoreCount();

         aGrpPtr->groupInfo = aGid;
         aGrpPtr->groupShares = 1;

         // Setup the control semaphore

         GETCNTLSEM(aSemPtr,aGrpPtr,aGrpPtr->groupSemCount);

         aSemPtr->maxSemValue = -1;
         aSemPtr->isRecursive = OFF;
         aSemPtr->isBalking = OFF;
         aSemPtr->semShares = 1;
         semctl( aGid, aGrpPtr->groupSemCount-1, SETVAL, 1 );

      }

      //
      // Otherwise we are a visitor
      //

      else
      {

         sprintf(&myTokenizer[strlen(myTokenizer)],".%d",theBase->creatorId);

         theControlGroup = new MutexSemaphoreGroup
            (
               0,
               myTokenizer,
               0,
               FAIL_IF_NOTEXISTS
            );

         GETCNTLSEM(aSemPtr,aGrpPtr,aGrpPtr->groupSemCount);

         // Increment the shares on the control group and control semaphore

         aGrpPtr->groupShares += 1;
         aSemPtr->semShares += 1;

      }

      //
      // Now we get our page control semaphore instance
      //

      theControlGroup->theGroupCSA = aGrpPtr;
      theInitializeFlag = false;
   }

   //
   // Destructor
   //

   SemaphoreCommon::~SemaphoreCommon( void )
   {
      if( theCSA != NULLPTR )
      {
         Memory::destroyStorage( theCSA );
         theCSA = NULLPTR;
      }
      else
      {
         ;  // do nothing
      }
   }

   // Retrieve the identifier

   Int   SemaphoreCommon::getOriginatorId( void ) const
   {
      return theBase->creatorId;
   }

   Int   SemaphoreCommon::canonicalUndefined( void )
   {
      CSAGrpHeaderPtr   aGrpPtr( (CSAGrpHeaderPtr)theBase );
      ++aGrpPtr;
      aGrpPtr->groupShares -= 1;
      return aGrpPtr->groupShares;
   }

   // Registering groups

   void  SemaphoreCommon::registerGroup( SemaphoreGroupPtr aGroup )
   {
      REQUIRE( aGroup != NULLPTR );

      //
      // Lock up control
      //

      CSAGrpHeaderPtr   aCntrlGrp(theControlGroup->theGroupCSA);
      CSASemHeaderPtr   aCntrlSem( NULLPTR );

      GETCNTLSEM(aCntrlSem,aCntrlGrp,aCntrlGrp->groupSemCount);
      LOCKSEM(aCntrlGrp->groupInfo,aCntrlGrp->groupSemCount,aCntrlSem);

      //
      // Setup the work
      //

      struct   
         semid_ds                   semds;
         SemaphoreGroupIdentifier   aSid(aGroup->getIdentifier());
         Int                        anId( (Int)aSid );

      semctl( anId, 0, IPC_STAT, &semds );

      Int      aSemCnt( semds.sem_nsems );

      CSAGrpHeaderPtr   aGrpPtr( (CSAGrpHeaderPtr)theBase );
      ++aGrpPtr;

      //
      // Best case, we are the first
      //

      if( theBase->currentUsed == 0 )
      {
         theBase->currentGrps = 1;
         aGrpPtr->groupSemCount = theBase->currentUsed  = aSemCnt;
         aGrpPtr->groupShares = 1;
         aGrpPtr->groupInfo = anId;
      }
      else
      {

         CSAGrpHeaderPtr   aHeadGrpPtr( aGrpPtr );
         CSASemHeaderPtr   aGroupSem( NULLPTR );

         //
         // Search for 
         //

         aGrpPtr = this->findGroup(anId,theBase->currentGrps,aHeadGrpPtr);

         //
         // Find last if search came up empty
         //

         if( aGrpPtr == NULLPTR )
         {
            aGrpPtr = this->findAvailableGroup
                           (
                              theBase->currentGrps,
                              aSemCnt,
                              aHeadGrpPtr
                           );

            //
            // We may need to adjust the CSA entries to make room for this
            // group
            //

            if( aGrpPtr == NULLPTR )
            {
               // First try subsetting

               aGrpPtr = this->subsetGroup(aSemCnt,aHeadGrpPtr);

               if( aGrpPtr == NULLPTR )
               {
                  // Okay, try combining

                  aGrpPtr = this->combineGroup(aSemCnt,aHeadGrpPtr);
               }
               else
               {

               }

               // We are out of resources or have a serious bug

               if( aGrpPtr == NULLPTR )
               {
                  UNLOCKSEM
                     (
                        aCntrlGrp->groupInfo,
                        aCntrlGrp->groupSemCount,
                        aCntrlSem
                     );

                  throw NullPointerException(LOCATION);
               }
            }
            else
            {
               ;  // do nothing
            }

            GETCNTLSEM(aGroupSem,aGrpPtr,aSemCnt);

            //
            // GroupInfo is either 0 or -1
            //

            if( aGrpPtr->groupInfo == 0 )
            {
               //
               // If we are the first entry, we initialize
               // and set the control semaphore accordingly
               //

               theBase->currentGrps += 1;
               theBase->currentUsed  += aSemCnt;
               aGrpPtr->groupSemCount = aSemCnt;

            }
            else
            {
               ;  // do nothing
            }

            aGroupSem->maxSemValue = -1;
            aGroupSem->isRecursive = OFF;
            aGroupSem->isBalking = OFF;
            semctl( anId, aSemCnt-1, SETVAL, 1 );

            aGrpPtr->groupInfo = anId;
         }
         else
         {
            GETCNTLSEM(aGroupSem,aGrpPtr,aSemCnt);
         }

         //
         // Update information
         //

         aGroupSem->semShares += 1;
         aGrpPtr->groupShares += 1;
      }

      aGroup->theGroupCSA = aGrpPtr;
      UNLOCKSEM(aCntrlGrp->groupInfo,aCntrlGrp->groupSemCount,aCntrlSem);
   }

   //
   // Take a group out of the share zone
   //

   Int  SemaphoreCommon::deregisterGroup( SemaphoreGroupPtr aGroup )
   {
      //
      // Lock up control
      //

      CSAGrpHeaderPtr   aCntrlGrp(theControlGroup->theGroupCSA);
      CSASemHeaderPtr   aCntrlSem( NULLPTR );

      GETCNTLSEM(aCntrlSem,aCntrlGrp,aCntrlGrp->groupSemCount);
      LOCKSEM(aCntrlGrp->groupInfo,aCntrlGrp->groupSemCount,aCntrlSem);

      Int                        results(0);
      CSAGrpHeaderPtr            aGrpPtr( aGroup->theGroupCSA );

      if( aGrpPtr != NULLPTR )
      {
         CSASemHeaderPtr   aGroupSem( NULLPTR );

         GETCNTLSEM(aGroupSem,aGrpPtr,aGrpPtr->groupSemCount);
         LOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);

         //
         // If this is the last one using the group,
         // we can mark if for reclaim
         //

         if( aGrpPtr->groupShares == 1 )
         {
            CSAGrpHeaderPtr   aNextGrpPtr( aGrpPtr );
            aNextGrpPtr += aGrpPtr->groupSemCount + 1;

            UNLOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);

            // If we are the tail, get rid of us

            if( aNextGrpPtr->groupInfo == 0 )
            {
               theBase->currentUsed -= aGrpPtr->groupSemCount;
               theBase->currentGrps -= 1;
               aGrpPtr->groupInfo = 0;
            }
            else
            {
               aGrpPtr->groupInfo = -1;
               aGrpPtr->groupShares = 0;
               aGrpPtr->groupType = -1;
               aGroupSem->semShares = 0;
            }
         }

         // Otherwise we just remove ourselves
         else
         {
            aGrpPtr->groupShares -= 1;
            aGroupSem->semShares -= 1;
            results = aGrpPtr->groupShares;
            UNLOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);
         }
      }
      else
      {
         results = -1;
      }

      UNLOCKSEM(aCntrlGrp->groupInfo,aCntrlGrp->groupSemCount,aCntrlSem);

      return results;
   }

   //
   // Attempt to take initial ownership of a 
   // specific semaphore or one that is available
   //

   Int   SemaphoreCommon::claimSemaphore
      (
         SemaphoreGroupPtr aGroup,
         Int               aSemIndex,
         IntRef            aMaxValue,
         IntRef            aRecurse,
         IntRef            aBalking,
         Int               aFailConstraint
      )
   {
      //
      // Lock up the group
      //

      CSAGrpHeaderPtr   aGrpPtr( aGroup->theGroupCSA );
      CSASemHeaderPtr   aGroupSem( NULLPTR );

      GETCNTLSEM(aGroupSem,aGrpPtr,aGrpPtr->groupSemCount);
      LOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);

      Int               results(0);
      CSASemHeaderPtr   aCandidateSem( NULLPTR );
      Int               realCnt(aGrpPtr->groupSemCount-1);
      Int               anId( (Int)aGroup->theIdentifier );

      //
      // If a specific location is requested
      //

      if( aSemIndex != -1 )
      {
         if( aSemIndex < realCnt )
         {
            GETCNTLSEM(aCandidateSem,aGrpPtr,aSemIndex+1);

            // If the candidate is available

            if( aCandidateSem->semShares == 0 )
            {
               // If it should have been in existence

               if( aFailConstraint == MUST_EXIST )
               {
                  results = SEMPHORE_UNAVAILABLE;
               }

               // Otherwise we can use it

               else
               {
                  aCandidateSem->semShares = 1;
                  aCandidateSem->maxSemValue = aMaxValue;
                  aCandidateSem->isRecursive = aRecurse;
                  aCandidateSem->isBalking = aBalking;
                  results = aSemIndex;
                  semctl( anId, aSemIndex, SETVAL, aMaxValue );
               }
            }
            else
            {
               if( aFailConstraint == MUST_NOTEXIST )
               {
                  results = SEMPHORE_UNAVAILABLE;
               }
               else
               {
                  aCandidateSem->semShares += 1;
                  aRecurse = aCandidateSem->isRecursive;
                  aBalking = aCandidateSem->isBalking;
                  aMaxValue = aCandidateSem->maxSemValue;
                  results = aSemIndex;
               }
            }
         }
         else
         {
            results = SEMPHORE_UNAVAILABLE;
         }
      }

      //
      // Otherwise we are free to choose, existence test
      // is ignored, the candidate must be free
      //

      else
      {
         results = SEMPHORE_UNAVAILABLE;
         for( Int x=0; x < realCnt; ++x )
         {
            GETCNTLSEM(aCandidateSem,aGrpPtr,x+1);

            if( aCandidateSem->semShares == 0 )
            {
               results = x;
               aCandidateSem->semShares = 1;
               aCandidateSem->maxSemValue = aMaxValue;
               aCandidateSem->isRecursive = aRecurse;
               aCandidateSem->isBalking = aBalking;
               semctl( anId, x, SETVAL, aMaxValue );
               x = realCnt;
            }
         }
      }

      UNLOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);

      return results;
   }

   //
   // Attempt to return ownership or share of a 
   // specific semaphore.
   //

   Int   SemaphoreCommon::reclaimSemaphore
      (
         SemaphoreGroupPtr aGroup,
         Int               aSemIndex
      )
   {
      //
      // Lock up the group
      //

      CSAGrpHeaderPtr   aGrpPtr( aGroup->theGroupCSA );
      CSASemHeaderPtr   aGroupSem( NULLPTR );

      GETCNTLSEM(aGroupSem,aGrpPtr,aGrpPtr->groupSemCount);
      LOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);

      Int               results(0);
      Int               realCnt(aGrpPtr->groupSemCount-1);

      if( aSemIndex >= 0 && aSemIndex < realCnt )
      {
         CSASemHeaderPtr   aCandidateSem( NULLPTR );
         GETCNTLSEM(aCandidateSem,aGrpPtr,aSemIndex+1);
         if( aCandidateSem->semShares > 0 )
         {
            aCandidateSem->semShares -= 1;
            results = aCandidateSem->semShares;
            if( results == 0 )
            {
               aCandidateSem->maxSemValue = 0;
               aCandidateSem->isRecursive = OFF;
               aCandidateSem->isBalking = OFF;
            }
            else
            {
               ;  // leave the settings alone
            }
         }
         else
         {
            results = -1;
         }
      }
      else
      {
         results = -1;
      }

      UNLOCKSEM(aGrpPtr->groupInfo,aGrpPtr->groupSemCount,aGroupSem);

      return results;
   }

   // Find the group in the collection

   CSAGrpHeaderPtr   SemaphoreCommon::findGroup
      ( 
         IntCref aGid, 
         IntCref aCount, 
         CSAGrpHeaderPtr aHead  
      )
   {
      CSAGrpHeaderPtr aGrpPtr( NULLPTR );

      for( Int x = 0; x < aCount; ++x )
      {
         if( aHead->groupInfo == aGid )
         {
            aGrpPtr = aHead;
            break;
         }
         else
         {
            aHead += (aHead->groupSemCount+1);
         }
      }
      return aGrpPtr;
   }

   // Find either a reusable same sized position, or
   // the tail

   CSAGrpHeaderPtr   SemaphoreCommon::findAvailableGroup
      ( 
         IntCref aCount, 
         IntCref aSemCount, 
         CSAGrpHeaderPtr aHead  
      )
   {
      CSAGrpHeaderPtr aGrpPtr( NULLPTR );

      for( Int x = 0; x < aCount; ++x )
      {
         if( aHead->groupInfo == -1 && aHead->groupSemCount == aSemCount )
         {
            aGrpPtr = aHead;
            break;
         }
         else
         {
            aHead += (aHead->groupSemCount+1);
         }
      }

      if( aGrpPtr == NULLPTR &&  aHead->groupInfo == 0 )
      {
         Int   testVal
            (
               aSemCount +
               theBase->currentUsed +
               theBase->currentGrps +
               1
            );

         if( testVal <= TOTALAVAILABLESLOTS )
         {
            aGrpPtr = aHead;
         }
         else
         {
            ;  // do nothing
         }
      }
      else
      {
         ;  // do nothing
      }

      return aGrpPtr;
   }

   //
   // Method for subsetting larger groups for smaller requests
   // 
     
   CSAGrpHeaderPtr  SemaphoreCommon::subsetGroup
      ( 
         Int aCountNeeded, 
         CSAGrpHeaderPtr aCntrlGroup 
      )
   {
      CSAGrpHeaderPtr   aGrp( NULLPTR );
      Int               aMax( theBase->currentGrps );

      // Look for a reusable slot

      for( Int x = 0; x < aMax && aGrp == NULLPTR; ++x )
      {
         if( aCntrlGroup->groupInfo == -1 )
         {
            if( aCntrlGroup->groupSemCount > aCountNeeded )
            {
               // Use current and jump to new marker

               aGrp = aCntrlGroup;
               aCntrlGroup += aCountNeeded+1;

               // Set new group marker

               aCntrlGroup->groupInfo = -1;
               aCntrlGroup->groupSemCount = 
                  (aGrp->groupSemCount - (aCountNeeded+1));

               aGrp->groupSemCount = aCountNeeded;
               aCntrlGroup = aGrp ;

               // We've decreased the semaphore count and
               // increased the group count

               theBase->currentUsed -= 1;   
               theBase->currentGrps += 1;
            }
            else
            {
               ;  // do nothing
            }
         }
         else
         {
            ;  // do nothing
         }

         aCntrlGroup += aCntrlGroup->groupSemCount+1;
      }

      return aGrp;
   }

   //
   // Method for combining adjacent groups for larger requests
   //

   CSAGrpHeaderPtr  SemaphoreCommon::combineGroup
      ( 
         Int aCountNeeded, 
         CSAGrpHeaderPtr aCntrlGroup 
      )
   {
      CSAGrpHeaderPtr   aGrp( aCntrlGroup );
      CSAGrpHeaderPtr   aGrpBegin( NULLPTR );
      Int               aMax( theBase->currentGrps );

      for( Int x = 0; x < aMax; )
      {
         if( aCntrlGroup->groupInfo == -1 )
         {
            // If we have not begun

            if( aGrpBegin == NULLPTR )
            {
               aGrpBegin = aCntrlGroup;
               ++x;
            }

            // Otherwise combine the group

            else
            {
               aGrpBegin->groupSemCount +=
                  (aCntrlGroup->groupSemCount + 1);

               // Emulate a dead semaphore

               aCntrlGroup->groupInfo = 
                  aCntrlGroup->groupShares = aCntrlGroup->groupSemCount = 0;

               --aMax;
               theBase->currentGrps -= 1;
               theBase->currentUsed += 1;   
               aCntrlGroup = aGrpBegin;
            }
         }
         else
         {
            aGrpBegin = NULLPTR;
            ++x;
         }
         aCntrlGroup += aCntrlGroup->groupSemCount+1;
      }

      return this->subsetGroup(aCountNeeded,aGrp);
   }

   //
   // Test for originating (ownership)
   //

   bool  SemaphoreCommon::isOriginator( void ) const
   {
      return theOriginator;
   }

   //
   // A shared semaphore group has been defined, register it
   //

   void  SemaphoreCommon::groupDefined( SemaphoreGroupPtr aGroup )
   {
      if( theInitializeFlag == false )
      {
         if( theInstance == NULLPTR )
         {
            createAttachment();
         }
         else
         {
            ;  // do nothing
         }

         theInstance->registerGroup(aGroup);
      }
      else
      {
         ;  // busy starting up
      }

      return ;
   }

   //
   // Semaphore group is being deleted
   //

   Int SemaphoreCommon::groupUnDefined( SemaphoreGroupPtr aGroup )
   {
      REQUIRE( aGroup != NULLPTR );
      Int   results(0);

      if( theControlGroup == aGroup )
      {
         results = theInstance->canonicalUndefined();  
      }
      else
      {
         results = theInstance->deregisterGroup(aGroup);
      }
      return results;
   }

   //
   // Check for local, and perform work
   //

   Int   SemaphoreCommon::setLock
      ( 
         SemaphoreGroupPtr aGroup, 
         Int               aGid,
         Int               aSid,
         Int               aFlg
      )
   {
      REQUIRE( aGroup != NULLPTR );

               Int      results(0);
      struct   sembuf   aSemBuf={ aSid, -1, aFlg};

      if( aGroup->isPrivate() == true )
      {
         results = semop( aGid, &aSemBuf, 1 );
      }
      else
      {
         CSAGrpHeaderPtr   aGrpPtr( aGroup->theGroupCSA );
         CSASemHeaderPtr   aGroupSem( NULLPTR );

         GETCNTLSEM(aGroupSem,aGrpPtr,aSid+1);

         results = semop( aGid, &aSemBuf, 1 );

         aGroupSem->semOwner = 
            (!results ? 
             (Int) Thread::getThreadIdentifier() : aGroupSem->semOwner);

      }
      return results;
   }

   //
   // Check for local, and perform work
   //

   Int   SemaphoreCommon::setUnLock
      ( 
         SemaphoreGroupPtr aGroup, 
         Int               aGid,
         Int               aSid,
         Int               aFlg
      )
   {
      REQUIRE( aGroup != NULLPTR );

               Int      results(0);
      struct   sembuf   aSemBuf={ aSid, 1, aFlg};

      if( aGroup->isPrivate() == true )
      {
         results = semop( aGid, &aSemBuf, 1 );
      }
      else
      {
         CSAGrpHeaderPtr   aGrpPtr( aGroup->theGroupCSA );
         CSASemHeaderPtr   aGroupSem( NULLPTR );

         GETCNTLSEM(aGroupSem,aGrpPtr,aSid+1);

         results = semop( aGid, &aSemBuf, 1 );

         aGroupSem->semOwner = 
            (!results ? (Int) 0 : aGroupSem->semOwner);
      }
      return results;
   }

   //
   // Check for local, and perform work
   //

   Int   SemaphoreCommon::waitZero
      ( 
         SemaphoreGroupPtr aGroup, 
         Int               aGid,
         Int               aSid,
         Int               aFlg
      )
   {
      REQUIRE( aGroup != NULLPTR );

               Int      results(0);
      struct   sembuf   aSemBuf={ aSid, 0, aFlg};

      if( aGroup->isPrivate() == true )
      {
         results = semop( aGid, &aSemBuf, 1 );
      }
      else
      {
         CSAGrpHeaderPtr   aGrpPtr( aGroup->theGroupCSA );
         CSASemHeaderPtr   aGroupSem( NULLPTR );

         GETCNTLSEM(aGroupSem,aGrpPtr,aSid+1);

         results = semop( aGid, &aSemBuf, 1 );

         aGroupSem->semOwner = 
            (!results ? (Int) 0 : aGroupSem->semOwner);
      }
      return results;
   }

   //
   // Attempt to take initial ownership of a 
   // specific semaphore or one that is available
   //

   Int   SemaphoreCommon::obtainSemaphore
      (
         SemaphoreGroupPtr aGroup,
         Int               aSemIndex,
         IntRef            aMaxValue,
         IntRef            aRecurse,
         IntRef            aBalking,
         Int               aFailConstraint
      )
   {
      REQUIRE( aGroup != NULLPTR );

      Int   results(0);

      if( aGroup->isPrivate() == true )
      {
         results = -1;
      }
      else
      {
         results = theInstance->claimSemaphore
            (
               aGroup,
               aSemIndex,
               aMaxValue,
               aRecurse,
               aBalking,
               aFailConstraint
            );
      }

      return results;
   }

   //
   // Drop a share on a sempahore
   //

   Int   SemaphoreCommon::relinquishSemaphore
      (
         SemaphoreGroupPtr aGroup,
         Int               aSemIndex
      )
   {
      Int   results(0);
      if( aGroup->isPrivate() == true )
      {
         ;  // do nothing
      }
      else
      {
         results = theInstance->reclaimSemaphore(aGroup,aSemIndex);
      }

      return results;
   }

   //
   // Set max value may be redundent
   //

   Int   SemaphoreCommon::setMaxValue
      ( 
         SemaphoreGroupPtr aGroup, 
         Int               aId, 
         Int               aValue 
      )
   {
      REQUIRE( aGroup != NULLPTR );
      Int   results(0);

      if( aGroup->isPrivate() == true )
      {
         semctl( (Int)aGroup->theIdentifier, aId, SETVAL, aValue );
      }
      else
      {
         ;  // do nothing
      }

      return results;
   }

   //
   // Get max value from the original value setting
   //

   Int   SemaphoreCommon::getSemaphoreMaxValue
      ( 
         SemaphoreGroupPtr aGroup, 
         Int               aSemId 
      )
   {
      REQUIRE( aGroup != NULLPTR );
      Int   results(0);

      if( aGroup->isPrivate() == true )
      {
         results = -1;
      }
      else
      {
         CSAGrpHeaderPtr   aGrpPtr( aGroup->theGroupCSA );
         CSASemHeaderPtr   aGroupSem( NULLPTR );

         GETCNTLSEM(aGroupSem,aGrpPtr,aSemId+1);

         results = aGroupSem->maxSemValue;
      }
      return results;
   }

   //
   // Called for instantiation
   //

   void  SemaphoreCommon::createAttachment( void )
   {
      if( theInstance == NULLPTR )
      {
         int   fhndl = 
            open( ourId, O_CREAT | O_EXCL, OWNER_ALL | GROUP_ALL | PUBLIC_ALL );

         if( fhndl != -1 )
         {
            close(fhndl);
         }

         theInstance = ::new SemaphoreCommon;
      }
      else
      {
         ;  // do nothing   
      }
   }

   //
   // Run-time shutdown of shared segment
   //

   void  SemaphoreCommon::exitAttachment(void)
   {
      if( theInstance != NULLPTR )
      {
         if( theControlGroup != NULLPTR )
         {
            ::delete theControlGroup;
            theControlGroup = NULLPTR;
         }
         else
         {
            ;  // do nothing
         }

         ::delete theInstance;
         theInstance = NULLPTR;
      }
      else
      {
         ;  // do nothing
      }
   }
}

/*
   Common rcs information do not modify
   $Author: dulimart $
   $Revision: 1.10 $
   $Date: 2000/11/13 20:15:36 $
   $Locker:  $
*/

