/**********************************************************************
 * This file was generated by coNCePTuaL on Mon Jul 24 17:32:30 2006
 * using the c_mpi backend (C + MPI).
 * Do not modify this file; modify /tmp/helloworld.ncptl instead.
 *
 * Entire source program
 * ---------------------
 *   All tasks mytask output "Hello from task " and mytask and "!".
 **********************************************************************/

/*****************
 * Include files *
 *****************/

/* Header files needed by all C-based backends */
#include <stdio.h>
#include <string.h>
#include <ncptl/ncptl.h>

/* Header files specific to the c_mpi backend */
#include <mpi.h>
#include <stdarg.h>

/**********
 * Macros *
 **********/

/* Define the maximum loop trip count that we're willing to unroll fully. */
#define CONC_MAX_UNROLL 5

/* Specify the number of trial iterations in each FOR <time> loop. */
#define CONC_FOR_TIME_TRIALS 10

/* Define a macro that rounds a double to a ncptl_int. */
#define CONC_DBL2INT(D) ((ncptl_int)((D)+0.5))

/* Estimate the number of unique communicators that this program will need.
 * (The tradeoff is one of initialization time versus memory consumption.) */
#define ESTIMATED_COMMUNICATORS 128

/* Specify an operation to use for all reduction operations. */
#define REDUCE_OPERATION MPI_SUM
#define REDUCE_OPERATION_NAME "MPI_SUM"

/*********************
 * Type declarations *
 *********************/

/* Define the type of event to perform. */
typedef enum {
  EV_SEND,                      /* Synchronous send */
  EV_ASEND,                     /* Asynchronous send */
  EV_RECV,                      /* Synchronous receive */
  EV_ARECV,                     /* Asynchronous receive */
  EV_WAIT,                      /* Wait for all asynchronous sends/receives to complete */
  EV_DELAY,                     /* Spin or sleep */
  EV_TOUCH,                     /* Touch a region of memory */
  EV_SYNC,                      /* Barrier synchronization */
  EV_RESET,                     /* Reset counters */
  EV_FLUSH,                     /* Compute aggregate functions for log-file columns */
  EV_MCAST,                     /* Synchronous multicast */
  EV_REDUCE,                    /* Reduction with or without a subsequent multicast */
  EV_BTIME,                     /* Beginning of a timed loop */
  EV_ETIME,                     /* Ending of a timed loop */
  EV_REPEAT,                    /* Repeatedly process the next N events */
  EV_SUPPRESS,                  /* Suppress writing to the log and standard output */
  EV_NEWSTMT,                   /* Beginning of a new top-level statement */
  EV_CODE,                      /* None of the above */
  NUM_EVS                       /* Number of event types in CONC_EVENT_TYPE */
} CONC_EVENT_TYPE;

/* Describe a synchronous or asynchronous send event. */
typedef struct {
  ncptl_int dest;               /* Destination task */
  ncptl_int size;               /* Number of bytes to send */
  ncptl_int alignment;          /* Message alignment (in bytes) */
  ncptl_int pendingsends;       /* # of outstanding sends */
  ncptl_int pendingrecvs;       /* # of outstanding receives */
  ncptl_int buffernum;          /* Buffer # to send from */
  int misaligned;               /* 1=misaligned from a page; 0=align as specified */
  int touching;                 /* 1=touch every word before sending */
  int verification;             /* 1=fill message buffer with known contents */
  void *buffer;                 /* Pointer to message memory */
  MPI_Request *handle;          /* MPI handle representing an asynchronous send */
} CONC_SEND_EVENT;

/* Describe a synchronous or asynchronous receive event. */
typedef struct {
  ncptl_int source;             /* Source task */
  ncptl_int size;               /* Number of bytes to receive */
  ncptl_int alignment;          /* Message alignment (in bytes) */
  ncptl_int pendingsends;       /* # of outstanding sends */
  ncptl_int pendingrecvs;       /* # of outstanding receives */
  ncptl_int buffernum;          /* Buffer # to receive into */
  int misaligned;               /* 1=misaligned from a page; 0=align as specified */
  int touching;                 /* 1=touch every word after reception */
  int verification;             /* 1=verify that all bits are correct */
  void *buffer;                 /* Pointer to message memory */
  MPI_Request *handle;          /* MPI handle representing an asynchronous receive */
} CONC_RECV_EVENT;

/* Describe a wait-for-asynchronous-completions event. */
typedef struct {
  ncptl_int numsends;           /* # of sends we expect to complete. */
  ncptl_int numrecvs;           /* # of receives we expect to complete. */
  ncptl_int numrecvbytes;       /* # of bytes we expect to receive-complete */
  ncptl_int *touchedlist;       /* List of receives that need to be touched */
  ncptl_int numtouches;         /* # of elements in the above */
} CONC_WAIT_EVENT;

/* Describe a spin or sleep delay. */
typedef struct {
  uint64_t microseconds;        /* Length of delay in microseconds */
  int spin0sleep1;              /* 0=spin; 1=sleep */
} CONC_DELAY_EVENT;

/* Describe a barrier synchronization event. */
typedef struct {
  MPI_Comm communicator;        /* Set of tasks to synchronize */
} CONC_SYNC_EVENT;

/* Describe a walk over a memory-region. */
typedef struct {
  ncptl_int regionbytes;        /* Size in bytes of the region to touch */
  ncptl_int bytestride;         /* Stride in bytes to touch */
  ncptl_int numaccesses;        /* Number of words to touch */
  ncptl_int wordsize;           /* Size in bytes of each touch */
  ncptl_int firstbyte;          /* Byte offset of the first byte to touch */
} CONC_TOUCH_EVENT;

/* Describe a synchronous multicast event. */
typedef struct {
  ncptl_int source;             /* Source task */
  ncptl_int size;               /* Number of bytes to send */
  ncptl_int alignment;          /* Message alignment (in bytes) */
  ncptl_int pendingsends;       /* # of outstanding sends */
  ncptl_int pendingrecvs;       /* # of outstanding receives */
  ncptl_int buffernum;          /* Buffer # to send/receive from */
  int misaligned;               /* 1=misaligned from a page; 0=align as specified */
  int touching;                 /* 1=touch every word before sending */
  int verification;             /* 1=verify that all bits are correct */
  void *buffer;                 /* Pointer to message memory */
  MPI_Comm communicator;        /* Set of tasks to multicast to/from */
  int root;                     /* source's rank within communicator */
} CONC_MCAST_EVENT;

/* Describe a reduction event. */
typedef struct {
  ncptl_int numitems;           /* # of items to reduce */
  ncptl_int itemsize;           /* # of bytes per item */
  ncptl_int alignment;          /* Message alignment (in bytes) */
  ncptl_int pendingsends;       /* # of outstanding sends */
  ncptl_int pendingrecvs;       /* # of outstanding receives */
  ncptl_int buffernum;          /* Buffer # to send/receive from */
  int misaligned;               /* 1=misaligned from a page; 0=align as specified */
  int touching;                 /* 1=touch every word before sending/after receiving */
  int sending;                  /* 1=we're a sender */
  int receiving;                /* 1=we're a receiver */
  void *buffer;                 /* Pointer to message memory */
  void *altbuffer;              /* Pointer to additional message memory */
  MPI_Comm sendcomm;            /* Set of tasks to reduce from */
  MPI_Comm recvcomm;            /* Set of tasks to reduce to */
  MPI_Datatype datatype;        /* MPI datatype to reduce */
  int reducetype;               /* 0=reduce; 1=allreduce; 2=reduce+bcast */
  ncptl_int reduceroot;         /* Root task of the reduction if reducetype is 0 or 2 */
  ncptl_int bcastroot;          /* Root task of the multicast if reducetype is 2 */
} CONC_REDUCE_EVENT;

/* Describe an event representing the beginning of a timed loop. */
typedef struct {
  uint64_t usecs;               /* Requested loop duration */
  uint64_t starttime;           /* Time at which the loop state last changed */
  uint64_t itersleft;           /* # of iterations remaining */
  uint64_t previters;           /* # of iterations we performed last time */
  int prev_quiet;               /* Previous value of suppress_output */
  int timing_trial;             /* 1=performing a timing trial; 0=running for real */
  volatile int finished;        /* 1=time has expired; 0=still ticking */
} CONC_BTIME_EVENT;

/* Describe an event representing the end of a timed loop. */
typedef struct {
  ncptl_int begin_event;        /* Index into eventlist[] of the corresponding BTIME event */
} CONC_ETIME_EVENT;

/* Describe an event representing repetitions of subsequent events. */
typedef struct {
  ncptl_int end_event;          /* Index into eventlist[] of the last event to repeat */
  ncptl_int numreps;            /* # of repetitions to perform */
} CONC_REPEAT_EVENT;

/* Describe an event representing output suppression (either on or off). */
typedef struct conc_suppress_event {
  int quiet;                    /* 0=allow output; 1=suppress it */
  int prev_quiet;               /* Previous value of suppress_output */
  ncptl_int matching_event;     /* Event ID of the "suppression on" event */
} CONC_SUPPRESS_EVENT;

/* Describe an event representing arbitrary code to execute at run time. */
typedef struct {
  ncptl_int number;             /* Unique number corresponding to a specific piece of code */
  ncptl_int var_mytask;         /* Copy of var_mytask to use within a piece of code */
} CONC_CODE_EVENT;

/* Describe an arbitrary coNCePTuaL event. */
typedef struct {
  CONC_EVENT_TYPE type;         /* Type of event */
  union {
    CONC_SEND_EVENT send;       /* Send state */
    CONC_RECV_EVENT recv;       /* Receive state */
    CONC_WAIT_EVENT wait;       /* Wait-for-completions state */
    CONC_DELAY_EVENT delay;     /* State for spins and sleeps */
    CONC_TOUCH_EVENT touch;     /* State for memory touching */
    CONC_SYNC_EVENT sync;       /* Synchronization state */
    CONC_MCAST_EVENT mcast;     /* Multicast state */
    CONC_REDUCE_EVENT reduce;   /* Reduction state */
    CONC_BTIME_EVENT btime;     /* Timed-loop state */
    CONC_ETIME_EVENT etime;     /* Additional timed-loop state */
    CONC_REPEAT_EVENT rep;      /* Repeated-events state */
    CONC_SUPPRESS_EVENT suppress;       /* State for suppressing output */
    CONC_CODE_EVENT code;       /* State for arbitrary code */
  } s;
} CONC_EVENT;

/* Fully specify an arbitrary for() loop (used by FOR EACH). */
typedef struct {
  int integral;                 /* 1=integral values; 0=floating-point values */
  enum {                        /* Comparison of loop variable to end variable */
    CONC_LEQ,                   /* Increasing progression */
    CONC_GEQ                    /* Decreasing progression */
  } comparator;
  enum {                        /* How to increment the loop variable */
    CONC_ADD,                   /* Arithmetically */
    CONC_MULT,                  /* Geometrically increasing */
    CONC_DIV                    /* Geometrically decreasing */
  } increment;
  union {
    struct {
      ncptl_int loopvar;        /* Loop variable */
      ncptl_int prev_loopvar;   /* Previous value of loop variable */
      ncptl_int startval;       /* Initial value of loop variable */
      ncptl_int endval;         /* Value not to exceed */
      ncptl_int incval;         /* Loop-variable increment */
    } i;
    struct {
      double loopvar;           /* Loop variable */
      double prev_loopvar;      /* Previous value of loop variable */
      double startval;          /* Initial value of loop variable */
      double endval;            /* Value not to exceed */
      double incval;            /* Loop-variable increment */
    } d;
  } u;
} LOOPBOUNDS;

/********************
 * Global variables *
 ********************/

/* Variables exported to coNCePTuaL programs */
ncptl_int var_bytes_received = 0;       /* Total number of bytes received */
ncptl_int var_msgs_received = 0;        /* Total number of messages received */
ncptl_int var_bit_errors = 0;   /* Total number of bit errors observed */
ncptl_int var_total_msgs = 0;   /* Sum of messages sent and messages received */
ncptl_int var_msgs_sent = 0;    /* Total number of messages sent */
ncptl_int var_bytes_sent = 0;   /* Total number of bytes sent */
ncptl_int var_num_tasks = 1;    /* Number of tasks running the program */
ncptl_int var_elapsed_usecs = 0;        /* Elapsed time in microseconds */
ncptl_int var_total_bytes = 0;  /* Sum of bytes sent and bytes received */

/* Variables used internally by boilerplate code */
uint64_t starttime;             /* Time the clock was last reset (microseconds) */
ncptl_int pendingrecvs = 0;     /* Current # of outstanding receives */
ncptl_int pendingrecvbytes = 0; /* Current # of bytes in outstanding receives */
NCPTL_QUEUE *touchedqueue;      /* Queue of asynchronous receives to touch */
ncptl_int pendingsends = 0;     /* Current # of outstanding sends */
NCPTL_QUEUE *eventqueue;        /* List of coNCePTuaL events to perform */
int within_time_loop = 0;       /* 1=we're within a FOR <time> loop */
int suppress_output = 0;        /* 1=suppress output to stdout and the log file */
void *touch_region = NULL;      /* Memory region to touch */
ncptl_int touch_region_size = 0;        /* # of bytes in the above */
int virtrank;                   /* This task's virtual rank in the computation */
int physrank;                   /* This task's physical rank in the computation */
NCPTL_VIRT_PHYS_MAP *procmap;   /* Virtual to physical rank mapping */
char *logfiletmpl;              /* Template for the log file's name */
char *logfiletmpl_default;      /* Default value of the above */

/* Global variables specific to the c_mpi backend */
ncptl_int mpi_is_running = 0;   /* 1=MPI has been initialized */
NCPTL_QUEUE *recvreqQ;          /* List of MPI receive requests */
MPI_Request *recvrequests;      /* List version of recvreqQ */
NCPTL_QUEUE *recvstatQ;         /* List of MPI receive statuses */
MPI_Status *recvstatuses;       /* List version of recvstatQ */
NCPTL_QUEUE *sendreqQ;          /* List of MPI send requests */
MPI_Request *sendrequests;      /* List version of sendreqQ */
NCPTL_QUEUE *sendstatQ;         /* List of MPI send statuses */
MPI_Status *sendstatuses;       /* List version of sendstatQ */
NCPTL_SET *communicators;       /* Map from an array of processor flags to an MPI communicator */
MPI_Errhandler mpi_error_handler;       /* Handle to handle_MPI_error() */

/*************************
 * Function declarations *
 *************************/

/* Make MPI errors invoke ncptl_fatal(). */
void handle_MPI_error (MPI_Comm * comm, int *errcode, ...)
{
  va_list args;
  char errstring[MPI_MAX_ERROR_STRING];
  int errstrlen;

  va_start (args, errcode);
  if (MPI_Error_string (*errcode, errstring, &errstrlen) == MPI_SUCCESS)
    ncptl_fatal ("MPI run-time error: %s", errstring);
  else
    ncptl_fatal ("MPI aborted with unrecognized error code %d", *errcode);
  va_end (args);
}

 /* Perform the equivalent of MPI_Comm_rank() for an arbitrary process. */
int rank_in_MPI_communicator (MPI_Comm subcomm, int global_rank)
{
  MPI_Group world_group;        /* Group associated with MPI_COMM_WORLD */
  MPI_Group subgroup;           /* Group associate with subcomm */
  int subrank;                  /* global_rank's rank within subcomm */

  MPI_Comm_group (MPI_COMM_WORLD, &world_group);
  MPI_Comm_group (subcomm, &subgroup);
  MPI_Group_translate_ranks (world_group, 1, &global_rank, subgroup,
                             &subrank);
  return subrank;
}

/* Given an array of task in/out booleans return an MPI
 * communicator that represents the "in" tasks. */
MPI_Comm define_MPI_communicator (char *procflags)
{
  MPI_Comm *existing_comm;      /* Previously defined MPI communicator */
  MPI_Comm new_comm;            /* Newly defined MPI communicator */

  existing_comm =
    (MPI_Comm *) ncptl_set_find (communicators, (void *) procflags);
  if (existing_comm)
    return *existing_comm;
  (void) MPI_Comm_split (MPI_COMM_WORLD, (int) procflags[physrank], physrank,
                         &new_comm);
  (void) MPI_Errhandler_set (new_comm, mpi_error_handler);
  ncptl_set_insert (communicators, (void *) procflags, (void *) &new_comm);
  return define_MPI_communicator (procflags);
}

/* Allocate a new event of a given type and return a pointer to it. */
static CONC_EVENT *conc_allocate_event (CONC_EVENT_TYPE type)
{
  CONC_EVENT *newevent = ncptl_queue_allocate (eventqueue);

  newevent->type = type;
  return newevent;
}

/* Declare an exit handler that gets called automatically when the
 * program terminates, whether successfully or not. */
static void conc_exit_handler (void)
{
  if (mpi_is_running)
    MPI_Abort (MPI_COMM_WORLD, 1);
}

/* Initialize coNCePTuaL, the messaging layer, and this program itself. */
static void conc_initialize (int argc, char *argv[])
{
  /* Variables needed by all C-based backends */
  CONC_EVENT *eventlist;        /* List of events to execute */
  ncptl_int numevents;          /* Number of entries in eventlist[] */
  int help_only = 0;            /* 1=User specified --help; save time by skipping ncptl_init() */
  char *argv0 = strrchr (argv[0], '/') ? strrchr (argv[0], '/') + 1 : argv[0];  /* Base name of the executable program */
  int i;                        /* Generic loop variable */

  /* Declare all of our command-line arguments. */
  NCPTL_CMDLINE arguments[] = {
    {NCPTL_TYPE_STRING, NULL, "logfile", 'L', "Log-file template", {0}}
  };

  /* Incorporate the complete coNCePTuaL source code as an array
   * for use by ncptl_log_write_prologue(). */
  char *sourcecode[] = {
    "All tasks mytask output \"Hello from task \" and mytask and \"!\".",
    NULL
  };

  /* Variables specific to the c_mpi backend */
  int num_tasks;                /* int version of var_num_tasks needed by MPI_Comm_size() */
  char *procflags;              /* Array of 1s representing an all-task MPI communicator */
  MPI_Comm comm_world = MPI_COMM_WORLD; /* Copy of MPI_COMM_WORLD that we can take the address of */

  /* As a special case, if the command line contains --help, then skip
   * the coNCePTuaL initialization step. */
  for (i = 1; i < argc; i++)
    if (!strcmp (argv[i], "--"))
      break;
    else if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-?")) {
      argv[1] = "-?";           /* Guaranteed to work, even with getopt() */
      help_only = 1;
      break;
    }

  /* Perform various initializations specific to the c_mpi backend. */
  /* Initialize MPI. */
  (void) MPI_Init (&argc, &argv);
  mpi_is_running = 1;

  /* Initialize the coNCePTuaL run-time library. */
  if (!help_only)
    ncptl_init (NCPTL_RUN_TIME_VERSION, argv[0]);
  (void) atexit (conc_exit_handler);

  /* Initialize the communication routines needed by the c_mpi backend. */
  (void) MPI_Errhandler_create ((MPI_Handler_function *) handle_MPI_error,
                                &mpi_error_handler);
  (void) MPI_Errhandler_set (MPI_COMM_WORLD, mpi_error_handler);
  (void) MPI_Comm_rank (MPI_COMM_WORLD, &physrank);
  (void) MPI_Comm_size (MPI_COMM_WORLD, &num_tasks);
  var_num_tasks = (ncptl_int) num_tasks;

  /* Plug variables and default values into the NCPTL_CMDLINE structure. */
  arguments[0].variable = (CMDLINE_VALUE *) & logfiletmpl;
  logfiletmpl_default = (char *) ncptl_malloc (strlen (argv0) + 15, 0);
  sprintf (logfiletmpl_default, "%s-%%p.log", argv0);
  arguments[0].defaultvalue.stringval = logfiletmpl_default;

  /* Parse the command line. */
  mpi_is_running = 0;           /* Don't invoke MPI_Abort() after --help. */
  ncptl_parse_command_line (argc, argv, arguments,
                            sizeof (arguments) / sizeof (NCPTL_CMDLINE));
  if (help_only)
    ncptl_fatal
      ("Internal error in the c_generic backend: failed to exit after giving help");
  mpi_is_running = 1;

  /* Establish a mapping from (virtual) task IDs to (physical) ranks. */
  procmap = ncptl_allocate_task_map (var_num_tasks);
  virtrank = ncptl_physical_to_virtual (procmap, physrank);

  /* Allocate a variety of dynamically growing queues. */
  eventqueue = ncptl_queue_init (sizeof (CONC_EVENT));
  touchedqueue = ncptl_queue_init (sizeof (ncptl_int));

  /* Perform initializations specific to the c_mpi backend. */
  sendreqQ = ncptl_queue_init (sizeof (MPI_Request));
  sendstatQ = ncptl_queue_init (sizeof (MPI_Status));
  recvreqQ = ncptl_queue_init (sizeof (MPI_Request));
  recvstatQ = ncptl_queue_init (sizeof (MPI_Status));
  communicators =
    ncptl_set_init (ESTIMATED_COMMUNICATORS, var_num_tasks * sizeof (char),
                    sizeof (MPI_Comm));
  procflags = (char *) ncptl_malloc (var_num_tasks * sizeof (char), 0);
  for (i = 0; i < var_num_tasks; i++)
    procflags[i] = 1;
  ncptl_set_insert (communicators, (void *) procflags, (void *) &comm_world);
  ncptl_free (procflags);

 /****************************************************
  * Generated, program-specific initialization code. *
  ****************************************************/

  /* ALL TASKS var_mytask OUTPUT ['"Hello from task "', 'var_mytask', '"!"'] */
  {                             /* ALL TASKS var_mytask */
    ncptl_int var_mytask = virtrank;

    /* The current coNCePTuaL statement applies to our task. */
    CONC_EVENT *thisev = conc_allocate_event (EV_CODE);

    thisev->s.code.number = 0;
    thisev->s.code.var_mytask = var_mytask;
  }

 /*************************
  * More boilerplate code *
  *************************/

  /* Abort if the program will terminate with pending messages. */
  if (pendingsends && pendingrecvs)
    ncptl_fatal ("Neglected to await the completion of %" NICS
                 " asynchronous %s and %" NICS " asynchronous %s",
                 pendingsends, pendingsends == 1LL ? "send" : "sends",
                 pendingrecvs, pendingrecvs == 1LL ? "receive" : "receives");
  else if (pendingsends)
    ncptl_fatal ("Neglected to await the completion of %" NICS
                 " asynchronous %s", pendingsends,
                 pendingsends == 1LL ? "send" : "sends");
  else if (pendingrecvs)
    ncptl_fatal ("Neglected to await the completion of %" NICS
                 " asynchronous %s", pendingrecvs,
                 pendingrecvs == 1LL ? "receive" : "receives");

  /* Allocate memory for non-unique messages and asynchronous
   * message handles now that we know how much memory we need
   * to allocate. */
  eventlist = ncptl_queue_contents (eventqueue, 0);
  numevents = ncptl_queue_length (eventqueue);
  sendrequests = ncptl_queue_contents (sendreqQ, 0);
  recvrequests = ncptl_queue_contents (recvreqQ, 0);
  for (i = 0; i < numevents; i++) {
    CONC_EVENT *thisev = &eventlist[i]; /* Cache of the current event */

    switch (thisev->type) {
      default:
        break;
    }
  }
}

/* Process a subset of the events in a given event list. */
static void conc_process_events (CONC_EVENT * eventlist,
                                 ncptl_int firstev, ncptl_int lastev,
                                 ncptl_int numreps)
{
  CONC_EVENT *thisev;           /* Cache of the current event */
  CONC_EVENT *thisev_first = &eventlist[firstev];       /* Cache of the first event */
  ncptl_int i;                  /* Iterate over events. */
  ncptl_int j;                  /* Iterate over repetitions. */

  /* Process from event firstev to event lastev (both inclusive). */
  for (j = numreps; j > 0; j--)
    for (i = firstev, thisev = thisev_first; i <= lastev; i++, thisev++) {
      /* Declare variables needed by all C-based backends. */
      void *msgbuffer;          /* Send or receive buffer */

      /* Process a single event. */
      switch (thisev->type) {
        case EV_CODE:
          /* Execute an arbitrary piece of code. */
          switch (thisev->s.code.number) {
            case 0:
              /* ALL TASKS var_mytask OUTPUT ['"Hello from task "', 'var_mytask', '"!"'] */
              if (!suppress_output) {
                uint64_t stop_elapsed_usecs = ncptl_time ();

                var_elapsed_usecs = stop_elapsed_usecs - starttime;
                printf ("%s%.10lg%s\n", "Hello from task ",
                        (double) thisev->s.code.var_mytask, "!");
                starttime += ncptl_time () - stop_elapsed_usecs;
              }
              break;

            default:
              /* The C code generation module must be broken. */
              ncptl_fatal ("Internal error: unknown EV_CODE block %" NICS,
                           thisev->s.code.number);
              break;
          }
          break;

        default:
          /* The c_generic backend or the c_mpi backend must be broken. */
          ncptl_fatal ("Internal error: unknown event type %d", thisev->type);
          break;
      }
    }
}

/* Finish up cleanly and return a status code. */
static int conc_finalize (void)
{
  int exitcode = 0;             /* Program exit code (to pass to exit()) */

  /* Declarations specific to the c_mpi backend */
  int mpiresult;                /* Return code from MPI_Finalize() */

  /* Inform the run-time library that it's no longer needed. */
  ncptl_queue_empty (eventqueue);
  ncptl_free (eventqueue);
  ncptl_finalize ();

  /* Finalization code specific to the c_mpi backend */
  mpiresult = MPI_Finalize ();
  mpi_is_running = 0;
  exitcode = mpiresult != MPI_SUCCESS;

  /* Return an exit status code. */
  return exitcode;
}

/*************************************************************************/
/***************************** MAIN ROUTINE ******************************/
/*************************************************************************/

/* Program execution starts here. */
int main (int argc, char *argv[])
{
  /* Declare variables needed by all C-based backends. */
  CONC_EVENT *eventlist;        /* List of events to execute */
  ncptl_int numevents;          /* Number of entries in eventlist[] */

  /* ----- Initialization ----- */
  conc_initialize (argc, argv);
  eventlist = ncptl_queue_contents (eventqueue, 0);
  numevents = ncptl_queue_length (eventqueue);
  sendrequests = ncptl_queue_contents (sendreqQ, 0);
  sendstatuses = ncptl_queue_contents (sendstatQ, 0);
  recvrequests = ncptl_queue_contents (recvreqQ, 0);
  recvstatuses = ncptl_queue_contents (recvstatQ, 0);
  starttime = ncptl_time ();

  /* ----- Event-list processing ----- */
  conc_process_events (eventlist, 0, numevents - 1, 1);

  /* ----- Finalization ----- */
  return conc_finalize ();
}