// variable sized simple spmd program written by ian a. mason 
// may 18 @ une
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include "pvm3.h"
#define SELF "vsspmd"
#define TIDTAG 17
#define TOKTAG 13
int main(int argc,  char *argv[]){
  int *tids, mytid, me, daddy, numt, i, nproc, nchild,  info;
  long start_time = time(NULL);
  mytid = pvm_mytid();
  daddy = pvm_parent();
  if(daddy  ==  PvmNoParent){
    /* parent code */
    if ((argc != 2) || 
        ((nproc  = atoi(argv[1])) <= 0)){
      fprintf(stderr, "Usage: %s ntasks\n", argv[0]);
      pvm_exit();
      exit(EXIT_FAILURE); };
    nchild = nproc - 1;
    if((tids = (int *)calloc(nproc, sizeof(int))) == NULL){
      fprintf(stderr, "Calloc failed\n");
      pvm_exit();
      exit(EXIT_FAILURE); 
    }
    me = 0;
    tids[0] = mytid;
    printf("i'm daddy with tid %d\n", tids[0]);
    printf("spawning %d children at t = %ld\n", 
           nchild,
           time(NULL) - start_time);
    numt = pvm_spawn(SELF, &argv[1], 0, "", nchild, &tids[1]);
    
    if( numt < nchild){
      printf("Aborting. Error codes are:\n");
      for( i = numt ; i < nchild ; i++ ) {
        printf("TID %d %d\n",i,tids[i]);
      }
      for( i = 1 ; i < numt ; i++ ){
        pvm_kill( tids[i] );
      }
      pvm_exit();
      exit(EXIT_FAILURE);
    }
    for( i = 1 ; i < nproc ; i++ )
      printf("child %d with id %d spawned\n", i, tids[i]);
    pvm_initsend(PvmDataDefault);
    pvm_pkint(&nproc, 1, 1);
    pvm_pkint(tids, nproc, 1);
    pvm_pklong(&start_time, 1, 1);
    info = pvm_mcast(&tids[1], nchild, TIDTAG);
    printf("mcast executed with info = %d\n", info);
  }
  else {
    /* child code */
    printf("i'm waiting for daddy\n");
    pvm_recv(daddy, TIDTAG);
    printf("i've heard from daddy\n");
    pvm_upkint(&nproc, 1, 1);
    //NB! the child needs to allocate space too!!
    tids = (int *) calloc(nproc, sizeof(int));
    pvm_upkint(tids, nproc, 1);
    pvm_upklong(&start_time, 1, 1);
    /* Determine which slave I am (1 -- nproc-1) */
    for( i = 1; i < nproc ; i++ )
      if( mytid == tids[i] ){ me = i; break; }
    printf("i'm child %d with tid %d at time = %ld\n", 
           i, 
           tids[i],
           time(NULL) - start_time);
  }
  /* ring code */
  {
    int token = 58;
    int dst = ( (me == (nproc - 1)) ? 0 : me + 1 );
    int src = ( (me == 0) ? (nproc - 1) : me - 1 );
    
    if( me == 0 ){ 
      pvm_initsend(PvmDataDefault );
      printf("sending token around the ring at time = %ld\n",  
             time(NULL) - start_time);
      pvm_pkint(&token, 1, 1);
      pvm_send(tids[dst], TOKTAG );
      pvm_recv(tids[src], TOKTAG );
      printf("token arrived back safely at time = %ld\n",  
             time(NULL) - start_time); }
    else {
      pvm_recv(tids[src], TOKTAG );
      pvm_upkint(&token, 1, 1);
      printf("i'm child %d and i got token %d at time = %ld\n", 
             i, 
             token,
             time(NULL) - start_time);
      //sleep(1);
      pvm_initsend(PvmDataDefault );
      pvm_pkint(&token, 1, 1);
      pvm_send(tids[dst],TOKTAG ); 
    }
    pvm_exit();
    exit(EXIT_SUCCESS);
  }
}