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

/** \example examp22.cpp
   This example is to show use of the EventSemaphoreGroup and EventSemaphore
   We do this by creating a number of threads that block on our wonderful
   event semaphore and, that's right, wait for the event to occur
*/                   

extern  "C"
{
    #include    <unistd.h>
}

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

#if   !defined(__EVENTSEMAPHOREGROUP_HPP)
#include <corelinux/EventSemaphoreGroup.hpp>
#endif

#if   !defined(__EVENTSEMAPHORE_HPP)
#include <corelinux/EventSemaphore.hpp>
#endif

#if !defined(__THREAD_HPP)
#include <corelinux/Thread.hpp>
#endif

#if !defined(__EVENTCONTEXT_HPP)
#include <EventContext.hpp>
#endif

using namespace corelinux;
using namespace std;

#include <iostream>
#include <exception>

//
// In module function prototypes
//

int   main( void );

//
// General Functions 
//

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

//
// Thread entry point declarations
//

Int   eventTest( EventSemaphoreGroupPtr );


//
// Global data
//

static  SemaphoreIdentifier gSemId(0);
const   ThreadIdentifier    badThread(-1);    // Error identifier

//
// Main entry point
//


int main( void )
{

   cout << endl;

   //
   // Practice graceful exception management
   //

   // Create the semaphore group

   EventSemaphorePtr    aEventSem( NULLPTR );
   EventSemaphoreGroup  aGroup( 1 );


   try
   {
      //
      // Create the group, private, and initialize the
      // controller semaphore so we start out locked
      //

      aEventSem = EventSemaphorePtr
                  (
                  aGroup.createSemaphore( gSemId, FAIL_IF_EXISTS ) 
                  );

      //
      // Create the threads
      //

      EventContext   aContext1(eventTest,&aGroup);

      ThreadIdentifier  aThread1( Thread::startThread(aContext1) );

      if( aThread1 == badThread )
      {
         cout << "Thread error!" << endl;
      }
      else
      {
         cout << "Thread 1 created!" << endl; 
      }

      sleep(1);

      EventContext   aContext2(eventTest,&aGroup);

      ThreadIdentifier  aThread2( Thread::startThread(aContext2) );

      if( aThread2 == badThread )
      {
         cout << "Thread error!" << endl;
      }
      else
      {
         cout << "Thread 2 created!" << endl; 
      }

      sleep(1);

      //
      // Do some actions which emulate the event
      // notifications to the waiting threads
      //

      while (1)
      {

         cout << "Release event semaphore" << endl;
         aEventSem->release();

         sleep(2);
         aEventSem->post();
      }
      cout << "Cleaning up" << endl;


      //
      // Cleanup
      //

      cout << "Return code from thread1 wait = " << 
      Thread::waitForThread(aThread1) << endl;

      cout << "Return code from thread2 wait = " << 
      Thread::waitForThread(aThread2) << endl;

      aGroup.destroySemaphore( aEventSem );
      aEventSem = NULLPTR;

   }

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

   if( aEventSem != NULLPTR )
   {
      aGroup.destroySemaphore( aEventSem );
      aEventSem = NULLPTR;
   }
   else
   {
      ;    //  do nothing
   }

   return 0;               
}

//
// Some utility functions
//

Int   eventTest( EventSemaphoreGroupPtr aGroupPtr )
{
   Int     rc(-1);

   if( aGroupPtr != NULLPTR )
   {
      EventSemaphorePtr    aEventSem( NULLPTR );

      try
      {

         aEventSem = EventSemaphorePtr
                     (
                     aGroupPtr->createSemaphore( gSemId, FAIL_IF_NOTEXISTS ) 
                     );

         while (1) 
         {
            rc = aEventSem->lockWithWait();
            if ( rc == SUCCESS )
               cout << "Semaphore obtained" << endl;
         }
         aGroupPtr->destroySemaphore( aEventSem ); 
         aEventSem = NULLPTR;

         rc = 0;
      }
      catch( ExceptionRef aException )
      {
         handleException(aException);
      }
      catch( ... )
      {
         cerr << "Unknown exception received" << endl;
      }

      if( aEventSem != NULLPTR )
      {
         aGroupPtr->destroySemaphore( aEventSem );
         aEventSem = NULLPTR;
      }
      else
      {
         ;   //  do nothing
      }

   }
   else
   {
      cout << "Ugly situation here" << endl;
   }

   return rc;
}


//
// 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: dulimart $
   $Revision: 1.4 $
   $Date: 2000/11/15 22:54:42 $
   $Locker:  $
*/


