#include <hpcxx_rts.h>
#include <iostream.h>
#include <unistd.h>
#include <stdio.h>

/***********************************************************************
tjs - 98.09.22

This example is to show the basic functioning of contexts.

To have different contexts using nexus, start the executable with:

executable -nx -n N

where N is the number of contexts you want -1

e.g.

my_prog -nx -n 3

would execute program my_prog using nexus and with 4 contexts.

98.09.29 tjs NOTE that most of the functions defined in HPCxx_Context
             are merely stubs and don't really do anything.  Those 
             functions in HPCxx_Group that are designed to create
             contexts don't work either.

***********************************************************************/
HPCxx_Mutex outLock;

class MyThread : public HPCxx_Thread {
  char *x;
  int myID;
  int myContext;
  unsigned slept_time;

public:
  MyThread(int _myID, int _myContext, const char *str) : 
    myID(_myID), myContext(_myContext), HPCxx_Thread(str){}
  void run() {

    sleep(1000*(10-myContext) + 100 * myID,0);

    outLock.lock();
    cout << "context: " << myContext << " ID: " << myID << " thread: "
      << getThreadID() 
      << endl << flush;
    outLock.unlock();

    //    outLock.lock();
    //    cout << "thread " << myID << " awake, slept " << 10-myID << endl << flush;
    //    outLock.unlock();

  }
};

int main(int argc, char **argv)
{
  // These two must come first
  HPCxx_Group *g;
  hpcxx_init(argc, argv, g);

  int
    i,
    num_threads,
    myContext;

  char
    t_name[40];

  //  cout << "how many threads do you want? " << flush;
  //  cin >> num_threads;

  myContext = g->getLocalIndex();

  num_threads = 3;

  // Array of threads
  MyThread *t[num_threads];

  outLock.lock();
  cout << "from context " << myContext << " spawning "
       << num_threads << " threads"
       << endl << flush;
  outLock.unlock();

  // spawn the threads
  for(i=0;i<num_threads;i++) {
    sprintf(t_name,"t_1_%d",i);
    t[i] = new MyThread(i,myContext,t_name);
    t[i]->start();
  }

  // Now the threads are running in parallel

  sleep(g->getLocalIndex());

  outLock.lock();
  cout << "g->getName: " << g->getName() << endl << flush;
  cout << "  g->getNumContexts: " << g->getNumContexts() << endl << flush;
  cout << "  g->getLocalIndex: " << g->getLocalIndex() << endl << flush;
  cout << "  g->getNumThreads: " << g->getNumThreads() << endl << flush;


  cout << "  thread names: " << endl << flush;
  // names of the threads
  for(i=0;i<num_threads;i++) {
    cout << "    * " << t[i]->getName() << "*" << endl << flush;
  }
  //  cout << "  g->isMasterContext: " << g->isMasterContext() << endl << flush;


  outLock.unlock();


  // join threads into single thread of execution
  for(i=0;i<num_threads;i++) {
    t[i]->join(10000,0);
  }

  // clean up hpcxx.  This should be the last thing you do.
  return hpcxx_exit(g);
}
