+#include "xbt/time.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_base, smpi,
+ "Logging specific to SMPI (base)");
+XBT_LOG_EXTERNAL_CATEGORY(smpi_base);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_bench);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_kernel);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_mpi);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_mpi_dt);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_coll);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_receiver);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_sender);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_util);
+
+void smpi_process_init(int* argc, char*** argv) {
+ int index;
+ smpi_process_data_t data;
+ smx_process_t proc;
+
+ proc = SIMIX_process_self();
+ index = atoi((*argv)[1]);
+ data = smpi_process_remote_data(index);
+ SIMIX_process_set_data(proc, data);
+ if (*argc > 2) {
+ free((*argv)[1]);
+ memmove(&(*argv)[1], &(*argv)[2], sizeof(char *) * (*argc - 2));
+ (*argv)[(*argc) - 1] = NULL;
+ }
+ (*argc)--;
+ DEBUG2("<%d> New process in the game: %p", index, proc);
+}
+
+void smpi_process_destroy(void) {
+ int index = smpi_process_index();
+
+ DEBUG1("<%d> Process left the game", index);
+}
+
+/* MPI Low level calls */
+MPI_Request smpi_mpi_isend(void* buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm) {
+ MPI_Request request;
+
+ request = xbt_new(s_smpi_mpi_request_t, 1);
+ request->comm = comm;
+ request->src = smpi_comm_rank(comm);
+ request->dst = dst;
+ request->tag = tag;
+ request->size = smpi_datatype_size(datatype) * count;
+ request->complete = 0;
+ request->data = request;
+ smpi_process_post_send(comm, request);
+ request->pair = SIMIX_network_isend(request->rdv, request->size, -1.0, buf, request->size, NULL);
+ return request;
+}
+
+MPI_Request smpi_mpi_irecv(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm) {
+ MPI_Request request;
+
+ request = xbt_new(s_smpi_mpi_request_t, 1);
+ request->comm = comm;
+ request->src = src;
+ request->dst = smpi_comm_rank(comm);
+ request->tag = tag;
+ request->size = smpi_datatype_size(datatype) * count;
+ request->complete = 0;
+ request->data = MPI_REQUEST_NULL;
+ smpi_process_post_recv(request);
+ request->pair = SIMIX_network_irecv(request->rdv, buf, &request->size);
+ return request;
+}
+
+void smpi_mpi_recv(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm, MPI_Status* status) {
+ MPI_Request request;
+
+ request = smpi_mpi_irecv(buf, count, datatype, src, tag, comm);
+ smpi_mpi_wait(&request, status);
+}
+
+void smpi_mpi_send(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm) {
+ MPI_Request request;
+
+ request = smpi_mpi_isend(buf, count, datatype, src, tag, comm);
+ smpi_mpi_wait(&request, MPI_STATUS_IGNORE);
+}
+
+void smpi_mpi_sendrecv(void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf, int recvcount, MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Status* status) {
+ MPI_Request requests[2];
+ MPI_Status stats[2];
+
+ requests[0] = smpi_mpi_isend(sendbuf, sendcount, sendtype, dst, sendtag, comm);
+ requests[1] = smpi_mpi_irecv(recvbuf, recvcount, recvtype, src, recvtag, comm);
+ smpi_mpi_waitall(2, requests, stats);
+ if(status != MPI_STATUS_IGNORE) {
+ // Copy receive status
+ memcpy(status, &stats[1], sizeof(MPI_Status));
+ }
+}
+
+static void finish_wait(MPI_Request* request, MPI_Status* status) {
+ MPI_Request data = (*request)->data;
+
+ xbt_assert0(data != MPI_REQUEST_NULL, "Erroneous situation");
+ if(status != MPI_STATUS_IGNORE) {
+ status->MPI_SOURCE = (*request)->src;
+ status->MPI_TAG = (*request)->tag;
+ status->MPI_ERROR = MPI_SUCCESS;
+ status->_count = (*request)->size; // size in bytes
+ status->_cancelled = 0; // FIXME: cancellation of requests not handled yet
+ }
+ DEBUG3("finishing wait for %p [data = %p, complete = %d]", *request, data, data->complete);
+ // data == *request if sender is first to finish its wait
+ // data != *request if receiver is first to finish its wait
+ if(data->complete == 0) {
+ // first arrives here
+ data->complete = 1;
+ if(data != *request) {
+ // receveiver cleans its part
+ xbt_free(*request);
+ }
+ } else {
+ // second arrives here
+ if(data != *request) {
+ // receiver cleans everything
+ xbt_free(data);
+ }
+ SIMIX_rdv_destroy((*request)->rdv);
+ xbt_free(*request);
+ }
+ *request = MPI_REQUEST_NULL;
+}