/*
  CoreLinux++ 
  Copyright (C) 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.  
*/   

/**
   This utility is for use in analysis of the SemaphoreCommon CSA
*/                   

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

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

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

#include <iostream>
#include <exception>

using namespace corelinux;
using namespace std;

//
// In module function prototypes
//

int   main( int argc, char *argv[] );
void  showDetails( MemoryStoragePtr );
void  showHeader( CSAHeaderPtr );
void  showGroups( CSAGrpHeaderPtr );
void  showSemaphores( CSASemHeaderPtr );

//
// General Functions 
//

void  handleAssertion( AssertionCref );
void  handleException( ExceptionCref );

//
// Thread entry point declarations
//

//
// Global data
//

//
// Main entry point
//

int main( int argc, char *argv[] )
{

   cout << endl;


   //
   // Practice graceful exception management
   //

   MemoryStoragePtr  pStor( NULLPTR );

   try
   {
      try
      {
         pStor = Memory::createStorage("clsemcsa.csa",0,FAIL_IF_NOTEXISTS,PUBLIC_READ,READ_ONLY);

      }
      catch( StorageExceptionRef aStorExcp )
      {
         cerr << "No use of CSA evident" << endl;
         throw;
      }


      //
      // Setup signal handlers
      //

      //
      // Parse command lines
      //

      //
      // Perform desired functions
      //

      showDetails( pStor );

      //
      // Get out
      //

      Memory::destroyStorage( pStor );
      pStor = NULLPTR;
   }

   catch( StorageExceptionRef aSemExcp )
   {
      cerr << "Storage Exception Received" << endl;
      handleException(aSemExcp);
   }
   catch( AssertionRef aAssert )
   {
      handleAssertion(aAssert);
   }
   catch( ExceptionRef aException )
   {
      handleException(aException);
   }
   catch( std::exception & e )
   {
      cerr  << e.what() << endl;
   }
   catch( ... )
   {
      cerr  << "Unknown exception." << endl;
   }

   if( pStor != NULLPTR )
   {
      Memory::destroyStorage( pStor );
   }
   else
   {
      ;  // do nothing
   }

   return 0;               
}

//
// Shows the details by walking the tree
//


void  showDetails( MemoryStoragePtr aStoragePtr )
{
   CSAHeaderPtr      aBase = CSAHeaderPtr( *aStoragePtr );

   showHeader( aBase );

   CSAGrpHeaderPtr   aGrp = CSAGrpHeaderPtr( aBase );
   ++aGrp;

   cout << endl;
   cout << "CSA Group Information " << endl;
   for( Int x = 0; x < aBase->currentGrps; ++x )
   {
      showGroups( aGrp );
      aGrp += aGrp->groupSemCount+1;
      cout << endl;
   }
}


void showHeader( CSAHeaderPtr aHeader )
{
   cout << endl;
   cout << "CSA Header Descriptor" << endl;
   cout << "The owning process identifier : " << aHeader->creatorId << endl;
   cout << "Total number of sem groups    : " << aHeader->currentGrps << endl;
   cout << "Total number of semaphores    : " << aHeader->currentUsed << endl;

}

void  showGroups( CSAGrpHeaderPtr aGrpPtr )
{
   cout << "Group information identifier : " << aGrpPtr->groupInfo << endl;
   cout << "Number of shares for group   : " << aGrpPtr->groupShares << endl;
   cout << "Number of sems in group      : " << aGrpPtr->groupSemCount << endl;

   CSASemHeaderPtr   aSem = CSASemHeaderPtr( aGrpPtr );

   for( Int x = 0; x < aGrpPtr->groupSemCount; ++x )
   {
      ++aSem;
      cout  << "\tSemaphore " << x << " details:" << endl;
      showSemaphores(aSem);
   }
}

void  showSemaphores( CSASemHeaderPtr aSemPtr )
{
   cout << "\t\tLast known semaphore owner : " << aSemPtr->semOwner << endl;
   cout << "\t\tValue for semaphore        : " ;
   if( aSemPtr->maxSemValue == Int(-1) )
   {
      cout << "Group Controller" << endl;
   }
   else
   {
      cout << aSemPtr->maxSemValue << endl;
   }

   cout << "\t\tRecursive flag             : " << (aSemPtr->isRecursive ? "true" : "false" ) << endl;
   cout << "\t\tBalking flag               : " << (aSemPtr->isBalking ? "true" : "false" ) << endl;
   cout << "\t\tShares on this semaphore   : " << aSemPtr->semShares  << endl;
}

//
// Error handlers
//

void  handleAssertion( AssertionCref aAssert )
{
   cerr << aAssert.getFile() << ":" << aAssert.getLine() << ":" << 
      "Assertion: ";

   if( aAssert.getType() == Assertion::NEVERGETHERE )
   {
      cerr << "NEVER_GET_HERE";
   }
   else
   {
      if( aAssert.getType() == Assertion::REQUIRE )
      {
         cerr  << "REQUIRE";
      }
      else if( aAssert.getType() == Assertion::ENSURE )
      {
         cerr  << "ENSURE";
      }
      else if( aAssert.getType() == Assertion::CHECK )
      {
         cerr  << "CHECK";
      }
      else 
      {
         cerr  << "ASSERT";
      }
      cerr << "( " << aAssert.getWhy() << " )";
   }

   cerr << endl;
}

void  handleException( ExceptionCref aExcp )
{
   cerr << aExcp.getFile() << ":" << aExcp.getLine() << ":" <<
      "Exception: " << aExcp.getWhy() << endl;
}

/*
   Common rcs information do not modify
   $Author: frankc $
   $Revision: 1.1 $
   $Date: 2000/06/10 19:51:06 $
   $Locker:  $
*/


