
/*
  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(__MUTEXSEMAPHORE_HPP)
#include <MutexSemaphore.hpp>
#endif

#include <sys/sem.h>

namespace corelinux
{

   //
   // Default constructor not allowed
   //

   MutexSemaphore::MutexSemaphore( void ) throw(Assertion)
      :
      Semaphore()
   {
      NEVER_GET_HERE;
   }

   //
   // Copy constructor not allowed
   //

   MutexSemaphore::MutexSemaphore( MutexSemaphoreCref ) throw(Assertion)
      :
      Semaphore()
   {
      NEVER_GET_HERE;
   }

   //
   // Default Constructor
   //

   MutexSemaphore::MutexSemaphore
      ( 
         SemaphoreGroupPtr aGroup,
         SemaphoreIdentifierRef aIdentifier,
         bool aAutoLockFlag,
         bool aRecursionFlag,
         bool aBalkingFlag
      ) throw ( NullPointerException )
      :
      Semaphore(aGroup,aIdentifier,aRecursionFlag,aBalkingFlag)
   {

      setValue(1);

      if( aAutoLockFlag == true )
      {
         this->lockWithWait();
         Semaphore::setOwnerId();
      }
      else
      {
         ;  // do nothing
      }
   }

   //
   // Destructor
   //

   MutexSemaphore::~MutexSemaphore( void )
   {
      ;  // do nothing
   }

   //
   // Returns true if lock value == 0
   //

   bool  MutexSemaphore::isLocked( void )
   {
      return !( getValue() );
   }

   //
   // Call for lock with wait disposition
   //

   SemaphoreOperationStatus MutexSemaphore::lockWithWait( void )
      throw(SemaphoreException)
   {

      SemaphoreOperationStatus   aStatus(SUCCESS);
      Guard                      myGuard( Synchronized::access() );

      //
      // If not yet locked, go quickly
      //

      if( getOwnerId().getScalar() == 0 )
      {
         myGuard.release();
         if( ( aStatus = setLock(0) ) == SUCCESS )
         {
            Semaphore::setOwnerId();
         }
         else
         {
            ;  // do nothing, error will be returned
         }
      }

      //
      // Otherwise if locked 
      //

      else 
      {
         // if balking

         if( isBalkingEnabled() == true )
         {
            aStatus = BALKED;
         }
         else
         {
            ; // do nothing
         }

         //
         // even with balking, if we allow recursion
         // and we are the same thread
         // then recurse
         //

         if( isRecursionEnabled() == true && 
             Thread::getThreadIdentifier() == getOwnerId() )
         {
            ++(*this);
            aStatus = SUCCESS;
         }

         // If I am not balked

         else if( aStatus != BALKED )
         {
            myGuard.release();
            if( ( aStatus = setLock(0) ) == SUCCESS )
            {
               Semaphore::setOwnerId();
            }
            else
            {
               ;  // do nothing, error
            }
         }
         else
         {
            ;  // do nothing, balked
         }
      }


      return aStatus;
   }

   //
   // Call for lock without waiting
   //

   SemaphoreOperationStatus MutexSemaphore::lockWithNoWait( void )
      throw( SemaphoreException )
   {
      GUARD;
      SemaphoreOperationStatus   aStatus(UNAVAILABLE);

      //
      // If not locked, push through
      //

      if( getOwnerId().getScalar() == 0 )
      {
         if( ( aStatus = setLock(IPC_NOWAIT) ) == SUCCESS )
         {
            Semaphore::setOwnerId();
         }
         else
         {
            ;  // do nothing or exception?
         }
      }

      //
      // If we are locked
      //

      else
      {
         // if balking enabled

         if( isBalkingEnabled() == true )
         {
            aStatus = BALKED;
         }
         else
         {
            ;  // do nothing, unavailable covered
         }

         //
         // even with balking, if recursion is
         // allowed AND we are the owner
         //

         if( isRecursionEnabled() == true && 
             Thread::getThreadIdentifier() == getOwnerId() )
         {
            ++(*this); 
            aStatus = SUCCESS;
         }
         else
         {
            ; // do nothing for recurs == false
              // or if it is and we are not the owner
              // because UNAVAILABLE and BALKED cover
              // the bases
         }
      }

      return aStatus;
   }

   //
   // Call release for lock
   //

   SemaphoreOperationStatus MutexSemaphore::release( void )
      throw(SemaphoreException)
   {
      GUARD;
      SemaphoreOperationStatus   aStatus( SUCCESS );
      ThreadIdentifier           aThread( Thread::getThreadIdentifier() );
      Word                       aLen( getRecursionQueueLength() );

      //
      // Take the fast way if possible
      //

      if( aLen == 0 )
      {
         if( ( aStatus = setUnlock( IPC_NOWAIT ) ) == SUCCESS )
         {
            Semaphore::resetOwnerId();
         }
         else
         {
            ;  // do nothing, error 
         }
      }
      else
      {
         //
         // Otherwise, if we have recursed we decrement
         // and check for true unlock
         //

         if( getOwnerId() == Thread::getThreadIdentifier() )
         {
            --(*this);
            --aLen;

            if( aLen == 0 )
            {
               if( ( aStatus = setUnlock( IPC_NOWAIT ) ) == SUCCESS )
               {
                  Semaphore::resetOwnerId();
               }
               else
               {
                  ;  // do nothing, error 
               }
            }
            else
            {
               ;  // do nothing, more to go
            }
         }

         //
         // Otherwise, we can't release the
         // lock on behalf of another thread
         // when we have a recursion
         //

         else
         {
            aStatus = UNAVAILABLE;
         }
      }

      return aStatus;
   }
}

/*
   Common rcs information do not modify
   $Author: frankc $
   $Revision: 1.4 $
   $Date: 2000/06/02 11:51:52 $
   $Locker:  $
*/


