/* libmpp.c: The TASS primitive message-passing library.
 * This library provides functions which can be composed to form
 * more complex message-passing functions, such as those of MPI.
 */
 
 /* Types */
 
typedef struct MPP_Comm_Record {
  int id;
} MPP_Comm_Record;
 
typedef struct MPP_Buffer {
  int id;
} MPP_Buffer;

typedef struct MPP_Op {
  int id;
} MPP_Op;

collective operation
 

 
 need to define types, dynamic types, constants
 
 constant:
 grammar: identifier, same as variable, but no declaration.
 add declaration.  then added to model.   just need way to evaluate them.
 f(..., MPI_ANY_SOURCE, ...)
 input, with assumption, ...
 so when adding MPI library, add input variables MPI_ANY_SOURCE, etc.
 
shared int MPI_ANY_SOURCE = -1;
shared int MPI_ANY_TAG = -2;
shared MPI_Op SUM = { .id = 1 };
shared MPI_Op MAX = { .id = 2 };

 
 system type MPP_Comm_Record
 system type MPP_Buffer

/* Note: MPP_Comm_Record is an internal type (like Message) but will have the
   following info:
   
  kind: enumerated type {...}
  channel: int
  source: int
  dest: int
  buffer: MPP_Buffer
  data: value  
  count: int
  tag: int
  bufferable: boolean
  probeable: boolean
  cancelable: boolean
  toBeFreed: boolean
  persistent: boolean
  testable: boolean
  collectiveKind: {NONE, BCAST, BARRIER, REDUCE, ALLREDUCE, ...}
  reductionOp: MPI_OP
  
  /* In Request...*/
  cancelable, toBeFreed, persistent, testable: boolean
  buffer: void*
  
  /* In RecvRequest... */
  
  /* In SendRequest... */
  destination: int
  bufferable, probeable: boolean
  
  /* In Message...*/
  destination: int
  probeable: boolean
  message: array
  
  /* In DischargedReceivedRequest... */
  status: StatusValueIF
  
  
  


/* Need to add a process (MPP Daemon).  How to do that with library?
 * Can define functions.  This is a special library.    */

/* Need way to declare certain memory off limits. Pointer, length, etc. */

/* Need memcpy */

/* message: sequence of primitive values? */

/* like array of anythings */

/* need to read and write from this thing */

/* memcpy(&x, &msg[i]) */

/* need special kind of value: vector of any things - symbolic value ? */

/* declare message boundaries, compute number of every kind of element, malloc
 * region using sizeof(...), memcpy each element there . Then send the region.
 * Separate pin operations guards memory and reports error if write attempt. 
 * If you do the pin, you might as well make it the post-send.
 * memory region: set of disjoint memory intervals.  Memory interval:
 * Start address, numBytes.  Value can be one big tuple or array of tuples.
 */
 
#pragma TASS constant
int MPP_ANY_SOURCE

#pragma TASS constant
int MPP_ANY_TAG

#pragma TASS system typedef MPI_Comm_Record


system typedef MPP_Buffer;

int MPP_getSize(MPP_Comm_Record request);

int MPP_getSource(MPP_Comm_Record request);

int MPP_getTag(MPP_Comm_Record request);


typedef MPP_Datatype int;

internally these could just be defined as record types, pointer types, etc.
// need library class for them, to add them to model.


/* Create a send request.  The buffer is defined as a sequence of intervals.
 * An interval is a contiguous memory region.  It is defined by a start point
 * and a size (in bytes).  The size is usually a linear combination of 
 * "sizeof" constants, e.g. 10*sizeof(int)+20*sizeof(double).  The sequence
 * of intervals is specified by two arrays of the same length, one giving the
 * start pointers, the other giving the sizes.  The destination PID is
 * also an argument, as is the message tag (a nonnegative integer or MPP_ANY_TAG),
 * and the channel (another integer).   Each channel provides a completely separate
 * communication universe, like communicators in MPI.  Note that the dest and source
 * arguments are absolute PIDs; there is no notion of rank relative to a communicator,
 * as in MPI.    A persistent request is one which is not automatically freed
 * after it completes (just like in MPI).   The source argument can also be 
 * MPP_ANY_SOURCE. */
MPP_Comm_Record MPP_send_init(boolean isPersistent, MPP_Buffer buffer, 
  int dest, int tag, int channel);
 
MPP_Comm_Record MPP_recv_init(boolean isPersistent, MPP_Buffer buffer,
  int source, int tag, int channel);

MPP_Buffer MPP_makeContiguousBuffer(void *start, int *size);

void MPP_start(MPP_Comm_Record *request);

boolean MPP_isFinished(MPI_Comm_Record *request);

void MPP_complete(MPP_Comm_Record *request); // status info is in comm record

void MPP_free(MPP_Comm_Record *request);

void MPP_upload(MPP_Comm_Record *sendRequest);
 
void MPP_download(MPP_Comm_Record *recvRequest);

void MPP_match(MPP_Comm_Record *send, MPP_Comm_Record *recv);

void MPP_synch(MPI_Comm_Record send);

void MPP_cancel(MPI_Comm_Record request);

// how should types be defined?  system?  or as records?

shared

Do we even need a system level library?
need daemon process: this just adds one process to the system.
Need shared variables: buffer....can just be arr
Need POR to be aware of what is going on.

MPI process can copy local vars in another process?
no/

post_send: record in request a buffer
post_recv: record in request a buffer...
upload(req): copy send buffer into system buffer
download(req): copy system buffer into recv buffer
wait

/* This should be a C file, same format as others, so can use
 * same front end */

/* make "system" a pragma */

/* mplib.mmp */

/* Sends a message to a process.  Produces a message and
 * inserts the message into a message queue.   The message
 * consists of a value, a destination process id, a tag, and
 * a channel.   The value is obtained by evaluating *buffer.
 * 
 * count could be something like 10*sizeof(int)?
 * think of MADRE where this would be re-configured
 * by getting sizeof datatypte....
 */
#pragma TASS system
void post_send(void *buffer, int size, int destination, int tag,
               int channel);

creates a message: what is type?  array of some length of value type
of *buffer.

need to be able to tell when buffer is accessed and declare
error.  For example, any assignment or any writing to array
must be watched.   This is something that every state must check.

derived datatype with bizzare stride: copy but keep

receive copy into.

derived datatypes and all that: need to declare them to
be buffers.  can't just copy

/* what to do for anysource, anytag? How about -1.  No any channel?
 * Result: what about count?
 * would like to get valueType info.  But no mechanism for that
 * in language.  
 * count?
 * can make all messages linear.
 */



create message, persistent send: specify buffer.  start: communication.

system void recv(void *buffer, int source, int tag, int channel,
  