#include <HPCxx_Profile.h>
#include <math.h>
#include <assert.h>
#include <iostream.h>
#include <hpcxx_rts.h>
#include <HPCxx_Sync.cc>
#include <hpcxx_invoke.cc>
#include <hpcxx_register.cc>
#include <HPCxx_GlobalPtr.cc>
#include <hpcxx_invokeImpl.cc>
#include <HPCxx_GlobalRefImpl.cc>

/***********************************************************************
tjs - 98.10.07

This example is to show the basic functioning of global pointers

Run this example with more than one context:

tim_rmfi_xmpl -nx -n N

where N is greater than 0

This example was mostly stolen from TestGP.

I don't know why but sometimes when this is run it hangs with the error
message:

select: protocol failure in circuit setup.

***********************************************************************/

HPCxx_Mutex outLock;


int hello(int context);

int hello(int context)
{
  outLock.lock();
  cout << "hello from beautiful context " << context << endl << flush;
  outLock.unlock();
  return(0);
}


int main(int argc, char* argv[])
{
  //
  // initialize HPC++
  //
  HPCxx_Group* group;
  hpcxx_init(argc, argv, group);

  //
  // all processes are executing in SPMD mode at this point
  //

  int numContexts = group->getNumContexts() - 1;
  int myContext = group->getLocalIndex();

  // get a pointer to the context ID of the context where
  // the function you want to invoke resides
  HPCxx_ContextID serverContext = *group->getContextID(0);

  // register the function.
  // ID of registered function does not need to be static
  int helloID = hpcxx_register(hello,10);
  int rtrnVal=999;

  // sleep is to insure that the serverContext doesn't go away.  It doesn't,
  // but I'm not sure what prevents that.
  if(myContext>0) {
    if(myContext == 1) {
      for(int i=0;i<10;i++) {
	cout << ". " << flush;
	sleep(1);
      }
      cout << endl << flush;
    } else {
      sleep(11);
    }
    // call the remotefunction arguments are
    // context in which to execute, the return value, the function ID,
    // and the argument.
    hpcxx_invoke(serverContext, rtrnVal, helloID, myContext);
  }

  outLock.lock();
  cout << "Context " << myContext << " rtrnVal " << rtrnVal << endl << flush;
  outLock.unlock();

  // Now with nonblocking

  // notice that the return val is a sync

  HPCxx_Sync<int> rtrnValSync;

  if(myContext>0) {
    if(myContext == 1) {
      for(int i=0;i<10;i++) {
	cout << ". " << flush;
	sleep(1);
      }
      cout << endl << flush;
    } else {
      sleep(11);
    }
    // call the remotefunction arguments are
    // context in which to execute, the return value, the function ID,
    // and the argument.
    hpcxx_ainvoke(serverContext, rtrnValSync, helloID, myContext);
  }

  // without the barrier, can context die before the remote invocation?
  // apprently not.  Apparently this barrier is not needed.
  //
  //  hpcxx_barrier();

  return hpcxx_exit(group);
}
