Even more MPI wrappers.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5740 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/auxprogs/mpiwrap.c b/auxprogs/mpiwrap.c
index 71c57c0..5e1e632 100644
--- a/auxprogs/mpiwrap.c
+++ b/auxprogs/mpiwrap.c
@@ -1078,8 +1078,8 @@
        && request_after == MPI_REQUEST_NULL
        && (error_in_status ? status->MPI_ERROR == MPI_SUCCESS : True)
        && ( (shadow=find_shadow_Request(request_before)) != NULL) ) {
-      /* The Irecv detailed in 'shadow' completed.  Make the result
-          buffer, and delete the entry. */
+      /* The Irecv detailed in 'shadow' completed.  Paint the result
+         buffer, and delete the entry. */
       if (count_from_Status(&recv_count, shadow->datatype, status)) {
          make_defined(shadow->buf, recv_count, shadow->datatype);
          if (opt_verbosity > 1)
@@ -1158,6 +1158,11 @@
 }
 
 /* --- Wait --- */
+/* The MPI1 spec (imprecisely) defines 3 request states:
+   - "null"     if the request is MPI_REQUEST_NULL
+   - "inactive" if not "null" and not associated with ongoing comms
+   - "active"   if not "null" and is associated with ongoing comms
+*/
 int WRAPPER_FOR(PMPI_Wait)( MPI_Request* request,
                             MPI_Status* status )
 {
@@ -1167,8 +1172,7 @@
    VALGRIND_GET_ORIG_FN(fn);
    before("Wait");
    check_writable_untyped(status, sizeof(MPI_Status));
-   if (*request != MPI_REQUEST_NULL)
-      check_readable_untyped(request, sizeof(MPI_Request));
+   check_readable_untyped(request, sizeof(MPI_Request));
    request_before = *request;
    CALL_FN_W_WW(err, fn, request,status);
    if (err == MPI_SUCCESS) {
@@ -1193,8 +1197,7 @@
    if (0) fprintf(stderr, "Waitall: %d\n", count);
    for (i = 0; i < count; i++) {
       check_writable_untyped(&statuses[i], sizeof(MPI_Status));
-      if (requests[i] != MPI_REQUEST_NULL)
-         check_readable_untyped(&requests[i], sizeof(MPI_Request));
+      check_readable_untyped(&requests[i], sizeof(MPI_Request));
    }
    requests_before = clone_Request_array( count, requests );
    CALL_FN_W_WWW(err, fn, count,requests,statuses);
@@ -1213,12 +1216,69 @@
    return err;
 }
 
+/* --- Test --- */
+/* nonblocking version of Wait */
+int WRAPPER_FOR(PMPI_Test)( MPI_Request* request, int* flag, 
+                            MPI_Status* status )
+{
+   MPI_Request  request_before;
+   OrigFn       fn;
+   int          err;
+   VALGRIND_GET_ORIG_FN(fn);
+   before("Test");
+   check_writable_untyped(status, sizeof(MPI_Status));
+   check_writable_untyped(flag, sizeof(int));
+   check_readable_untyped(request, sizeof(MPI_Request));
+   request_before = *request;
+   CALL_FN_W_WWW(err, fn, request,flag,status);
+   if (err == MPI_SUCCESS && *flag) {
+      maybe_complete(False/*err in status?*/, 
+                     request_before, *request, status);
+      make_defined_untyped(status, sizeof(MPI_Status));
+   }
+   after("Test", err);
+   return err;
+}
+
+/* --- Testall --- */
+/* nonblocking version of Waitall */
+int WRAPPER_FOR(PMPI_Testall)( int count, MPI_Request* requests,
+                               int* flag, MPI_Status* statuses )
+{
+   MPI_Request* requests_before = NULL;
+   OrigFn       fn;
+   int          err, i;
+   VALGRIND_GET_ORIG_FN(fn);
+   before("Testall");
+   if (0) fprintf(stderr, "Testall: %d\n", count);
+   check_writable_untyped(flag, sizeof(int));
+   for (i = 0; i < count; i++) {
+      check_writable_untyped(&statuses[i], sizeof(MPI_Status));
+      check_readable_untyped(&requests[i], sizeof(MPI_Request));
+   }
+   requests_before = clone_Request_array( count, requests );
+   CALL_FN_W_WWWW(err, fn, count,requests,flag,statuses);
+   /* Urk.  Is the following "if (...)" really right?  I don't know. */
+   if (*flag
+       && (err == MPI_SUCCESS /*complete success*/
+           || err == MPI_ERR_IN_STATUS /* partial success */)) {
+      Bool e_i_s = err == MPI_ERR_IN_STATUS;
+      for (i = 0; i < count; i++) {
+         maybe_complete(e_i_s, requests_before[i], requests[i], 
+                               &statuses[i]);
+         make_defined_untyped(&statuses[i], sizeof(MPI_Status));
+      }
+   }
+   if (requests_before)
+      free(requests_before);
+   after("Testall", err);
+   return err;
+}
+
 /* --- Iprobe --- */
-/* very unclear about this */
 /* pre:  must-be-writable: *flag, *status */
 /* post: make-readable *flag
-         if *flag==True  make-readable *status
-         if *flag==False make-uninitialised *status */
+         if *flag==True  make-defined *status */
 int WRAPPER_FOR(PMPI_Iprobe)(int source, int tag, 
                              MPI_Comm comm, 
                              int* flag, MPI_Status* status)
@@ -1234,13 +1294,48 @@
       make_defined_untyped(flag, sizeof(*flag));
       if (*flag)
          make_defined_untyped(status, sizeof(*status));
-      else
-         make_writable_untyped(status, sizeof(*status));
    }
    after("Iprobe", err);
    return err;
 }
 
+/* --- Probe --- */
+/* pre:  must-be-writable *status */
+/* post: make-defined *status */
+int WRAPPER_FOR(PMPI_Probe)(int source, int tag,
+                            MPI_Comm comm, MPI_Status* status)
+{
+   OrigFn fn;
+   int    err;
+   VALGRIND_GET_ORIG_FN(fn);
+   before("Probe");
+   check_writable_untyped(status, sizeof(*status));
+   CALL_FN_W_WWWW(err, fn, source,tag,comm,status);
+   make_defined_if_success_untyped(err, status, sizeof(*status));
+   after("Probe", err);
+   return err;
+}
+
+/* --- Cancel --- */
+/* Wrapping PMPI_Cancel is interesting only to the extent that we need
+   to be able to detect when a request should be removed from our
+   shadow table due to cancellation. */
+int WRAPPER_FOR(PMPI_Cancel)(MPI_Request* request)
+{
+   OrigFn      fn;
+   int         err;
+   MPI_Request tmp;
+   VALGRIND_GET_ORIG_FN(fn);
+   before("Cancel");
+   check_writable_untyped(request, sizeof(*request));
+   tmp = *request;
+   CALL_FN_W_W(err, fn, request);
+   if (err == MPI_SUCCESS)
+      delete_shadow_Request(tmp);
+   after("Cancel", err);
+   return err;
+}
+
 
 /*------------------------------------------------------------*/
 /*---                                                      ---*/
@@ -1397,7 +1492,8 @@
    CALL_FN_W_8W(err, fn, sendbuf,sendcount,sendtype,
                          recvbuf,recvcount,recvtype,
                          root,comm);
-   make_defined_if_success(err, recvbuf, recvcount * sz, recvtype);
+   if (me == root)
+      make_defined_if_success(err, recvbuf, recvcount * sz, recvtype);
    after("Gather", err);
    return err;
 }
@@ -1405,6 +1501,70 @@
 
 /*------------------------------------------------------------*/
 /*---                                                      ---*/
+/*--- Sec 4.6, Scatter                                     ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/* pre:  (root only): must be readable: (sendbuf,sendcount * comm_size,sendtype)
+         (all):       must be writable: (recvbuf,recvbuf,recvtype)
+   post: (all):       make defined: (recvbuf,recvbuf,recvtype)
+*/
+int WRAPPER_FOR(PMPI_Scatter)(
+       void* sendbuf, int sendcount, MPI_Datatype sendtype,
+       void* recvbuf, int recvcount, MPI_Datatype recvtype,
+       int root, MPI_Comm comm)
+{
+   OrigFn fn;
+   int    err, me, sz;
+   VALGRIND_GET_ORIG_FN(fn);
+   before("Scatter");
+   me = comm_rank(comm);
+   sz = comm_size(comm);
+   check_writable(recvbuf, recvcount, recvtype);
+   if (me == root)
+      check_readable(sendbuf, sendcount * sz, sendtype);
+   CALL_FN_W_8W(err, fn, sendbuf,sendcount,sendtype,
+                         recvbuf,recvcount,recvtype,
+                         root,comm);
+   make_defined_if_success(err, recvbuf, recvcount, recvtype);
+   after("Scatter", err);
+   return err;
+}
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- Sec 4.8, All-to-All Scatter/Gather                   ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/* pre:  (all) must be readable: (sendbuf,sendcount * comm_size,sendtype)
+         (all) must be writable: (recvbuf,recvcount * comm_size,recvtype)
+   post: (all) make defined:     (recvbuf,recvcount * comm_size,recvtype)
+*/
+int WRAPPER_FOR(PMPI_Alltoall)(
+       void* sendbuf, int sendcount, MPI_Datatype sendtype,
+       void* recvbuf, int recvcount, MPI_Datatype recvtype,
+       MPI_Comm comm)
+{
+   OrigFn fn;
+   int    err, sz;
+   VALGRIND_GET_ORIG_FN(fn);
+   before("Alltoall");
+   sz = comm_size(comm);
+   check_readable(sendbuf, sendcount * sz, sendtype);
+   check_writable(recvbuf, recvcount * sz, recvtype);
+   CALL_FN_W_7W(err, fn, sendbuf,sendcount,sendtype,
+                         recvbuf,recvcount,recvtype,
+                         comm);
+   make_defined_if_success(err, recvbuf, recvcount * sz, recvtype);
+   after("Alltoall", err);
+   return err;
+}
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
 /*--- Sec 4.9, Global Reduction Operations                 ---*/
 /*---                                                      ---*/
 /*------------------------------------------------------------*/
@@ -1792,7 +1952,7 @@
 DEFAULT_WRAPPER_W_8W(Allgatherv)
 DEFAULT_WRAPPER_W_3W(Alloc_mem)
 /* DEFAULT_WRAPPER_W_6W(Allreduce) */
-DEFAULT_WRAPPER_W_7W(Alltoall)
+/* DEFAULT_WRAPPER_W_7W(Alltoall) */
 DEFAULT_WRAPPER_W_9W(Alltoallv)
 DEFAULT_WRAPPER_W_9W(Alltoallw)
 DEFAULT_WRAPPER_W_2W(Attr_delete)
@@ -1804,7 +1964,7 @@
 DEFAULT_WRAPPER_W_7W(Bsend_init)
 DEFAULT_WRAPPER_W_2W(Buffer_attach)
 DEFAULT_WRAPPER_W_2W(Buffer_detach)
-DEFAULT_WRAPPER_W_1W(Cancel)
+/* DEFAULT_WRAPPER_W_1W(Cancel) */
 DEFAULT_WRAPPER_W_4W(Cart_coords)
 DEFAULT_WRAPPER_W_6W(Cart_create)
 DEFAULT_WRAPPER_W_5W(Cart_get)
@@ -1981,7 +2141,7 @@
 DEFAULT_WRAPPER_W_7W(Pack)
 DEFAULT_WRAPPER_W_4W(Pack_size)
 /* int MPI_Pcontrol(const int level, ...) */
-DEFAULT_WRAPPER_W_4W(Probe)
+/* DEFAULT_WRAPPER_W_4W(Probe) */
 DEFAULT_WRAPPER_W_3W(Publish_name)
 DEFAULT_WRAPPER_W_8W(Put)
 DEFAULT_WRAPPER_W_1W(Query_thread)
@@ -1997,7 +2157,7 @@
 /* DEFAULT_WRAPPER_W_6W(Rsend) */
 DEFAULT_WRAPPER_W_7W(Rsend_init)
 DEFAULT_WRAPPER_W_6W(Scan)
-DEFAULT_WRAPPER_W_8W(Scatter)
+/* DEFAULT_WRAPPER_W_8W(Scatter) */
 DEFAULT_WRAPPER_W_9W(Scatterv)
 DEFAULT_WRAPPER_W_7W(Send_init)
 /* DEFAULT_WRAPPER_W_6W(Send) */
@@ -2011,9 +2171,9 @@
 DEFAULT_WRAPPER_W_2W(Status_f2c)
 DEFAULT_WRAPPER_W_2W(Status_set_cancelled)
 DEFAULT_WRAPPER_W_3W(Status_set_elements)
-DEFAULT_WRAPPER_W_4W(Testall)
+/* DEFAULT_WRAPPER_W_4W(Testall) */
 DEFAULT_WRAPPER_W_5W(Testany)
-DEFAULT_WRAPPER_W_3W(Test)
+/* DEFAULT_WRAPPER_W_3W(Test) */
 DEFAULT_WRAPPER_W_2W(Test_cancelled)
 DEFAULT_WRAPPER_W_5W(Testsome)
 DEFAULT_WRAPPER_W_2W(Topo_test)