/*
  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 examp15.cpp
   This example is to show use of the initial Thread and ThreadContext.
   A couple of threads are executed to show off:
   
   1. Default operations
   2. Declaring a stack size
   3. Redirecting the context allocation to something that
   takes arguments.
   
   The last one may seem like overkill, we could have easily
   not substituted anything and had the caller entry point
   cast the ThreadContext to the ArgumentContext and extract
   any arguments, but then you wouldn't have a live example!      
*/                   


#include <Common.hpp>
#include <Thread.hpp>
#include <ArgumentContext.hpp>

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   threadTest( ThreadContextPtr );
Int   argumentTest( IntCref );

//
// Global data
//

const int               STACKSIZE(4096);  // Thread stack size
const ThreadIdentifier  badThread(-1);    // Error identifier

//
// Main entry point
//

int main( void )
{

   cout << endl;

   //
   // Practice graceful exception management
   //

   try
   {
      //
      // Our first example is a simple default thing.
      //

      // Setup the context with default stack and
      // handlers

      ThreadContext  aSimpleContext(threadTest);

      cout  << "Starting default context thread" << endl;

      //
      // Start the thread and wait for return
      //

      ThreadIdentifier  aThreadld( Thread::startThread(aSimpleContext) );

      if( aThreadld != badThread )
      {
         Int   aRc( Thread::waitForThread(aThreadld) );

         cout  << "Thread return code = " << aRc << endl;
      }
      else
      {
         cout << "Thread error!" << endl;
      }
      cout << endl;

      //
      // Now we try one with a smaller stack
      //

      ThreadContext     aStackChangedContext(threadTest,STACKSIZE);

      cout  << "Starting restacked context thread" << endl;

      aThreadld = Thread::startThread(aStackChangedContext);

      if( aThreadld != badThread )
      {
         Int   aRc( Thread::waitForThread(aThreadld) );

         cout  << "Thread return code = " << aRc << endl;
      }
      else
      {
         cout << "Thread error!" << endl;
      }
      cout << endl;

      //
      // Ok, now for the good stuff. We redirect the
      // context factory methods in the class so that
      // we provide a different context. We also set
      // the threadframe to invoke the call as declared
      //

      //
      // Provide holders for the sets
      //

      ArgumentContext   aArgContext(argumentTest,5);

      cout  << "Starting argument context thread" << endl;

      aThreadld = Thread::startThread(aArgContext);

      if( aThreadld != badThread )
      {
         Int   aRc( Thread::waitForThread(aThreadld) );

         cout  << "Thread return code = " << aRc << endl;
      }
      else
      {
         cout << "Thread error!" << endl;
      }

      cout << endl;

      // We are clean and return the settings to the
      // originals


      Thread::dump();


   }

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

   return 0;               
}

//
// Child thread implementation 
//

Int threadTest( ThreadContextPtr aContextPtr )
{

   Int   returnCode(0);

   try
   {
      cout  << "In Child!" << endl;
      cout  << "My identifier is " << 
         aContextPtr->getIdentifier().getScalar() << endl;
   }

   catch( ... )
   {
      cerr << "Thread bailing out with exception" << endl;
      throw;
   }

   return returnCode;
}

//
// Argument test thread implementation
//

Int argumentTest( IntCref aArgument )
{
   cout  << "Argument thread has arg value = " << aArgument << endl;

   return 0;
}

//
// 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: prudhomm $
   $Revision: 1.4 $
   $Date: 2000/08/31 22:49:02 $
   $Locker:  $
*/


