+
+void smpi_mpi_exscan(void *sendbuf, void *recvbuf, int count,
+ MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
+{
+ int system_tag = -888;
+ int rank, size, other, index;
+ MPI_Aint lb = 0, dataext = 0;
+ MPI_Request *requests;
+ void **tmpbufs;
+ int recvbuf_is_empty=1;
+ rank = smpi_comm_rank(comm);
+ size = smpi_comm_size(comm);
+
+ // FIXME: check for errors
+ smpi_datatype_extent(datatype, &lb, &dataext);
+
+ // Send/Recv buffers to/from others;
+ requests = xbt_new(MPI_Request, size - 1);
+ tmpbufs = xbt_new(void *, rank);
+ index = 0;
+ for(other = 0; other < rank; other++) {
+ // FIXME: possibly overkill we we have contiguous/noncontiguous data
+ // mapping...
+ tmpbufs[index] = smpi_get_tmp_sendbuffer(count * dataext);
+ requests[index] =
+ smpi_irecv_init(tmpbufs[index], count, datatype, other, system_tag,
+ comm);
+ index++;
+ }
+ for(other = rank + 1; other < size; other++) {
+ requests[index] =
+ smpi_isend_init(sendbuf, count, datatype, other, system_tag, comm);
+ index++;
+ }
+ // Wait for completion of all comms.
+ smpi_mpi_startall(size - 1, requests);
+ if(smpi_op_is_commute(op)){
+ for(other = 0; other < size - 1; other++) {
+ index = smpi_mpi_waitany(size - 1, requests, MPI_STATUS_IGNORE);
+ if(index == MPI_UNDEFINED) {
+ break;
+ }
+ if(index < rank) {
+ if(recvbuf_is_empty){
+ smpi_datatype_copy(tmpbufs[index], count, datatype, recvbuf, count, datatype);
+ recvbuf_is_empty=0;
+ }else
+ // #Request is below rank: it's a irecv
+ smpi_op_apply(op, tmpbufs[index], recvbuf, &count, &datatype);
+ }
+ }
+ }else{
+ //non commutative case, wait in order
+ for(other = 0; other < size - 1; other++) {
+ smpi_mpi_wait(&(requests[other]), MPI_STATUS_IGNORE);
+ if(index < rank) {
+ if(recvbuf_is_empty){
+ smpi_datatype_copy(tmpbufs[other], count, datatype, recvbuf, count, datatype);
+ recvbuf_is_empty=0;
+ }else smpi_op_apply(op, tmpbufs[other], recvbuf, &count, &datatype);
+ }
+ }
+ }
+ for(index = 0; index < rank; index++) {
+ smpi_free_tmp_buffer(tmpbufs[index]);
+ }
+ for(index = 0; index < size-1; index++) {
+ smpi_mpi_request_free(&requests[index]);
+ }
+ xbt_free(tmpbufs);
+ xbt_free(requests);
+}
+
+
+int smpi_keyval_create(MPI_Copy_function* copy_fn, MPI_Delete_function* delete_fn, int* keyval, void* extra_state){
+
+ if(!smpi_keyvals)
+ smpi_keyvals = xbt_dict_new();
+
+ smpi_key_elem value = (smpi_key_elem) xbt_new0(s_smpi_mpi_key_elem_t,1);
+
+ value->copy_fn=copy_fn;
+ value->delete_fn=delete_fn;
+
+ *keyval = keyval_id;
+
+ xbt_dict_set(smpi_keyvals,(const char*)keyval,(void*)value, NULL);
+ keyval_id++;
+ return MPI_SUCCESS;
+}
+
+int smpi_keyval_free(int* keyval){
+ smpi_key_elem elem = xbt_dict_get_or_null(smpi_keyvals, (const char*)keyval);
+ if(!elem)
+ return MPI_ERR_ARG;
+ xbt_dict_remove(smpi_keyvals, (const char*)keyval);
+ xbt_free(elem);
+ return MPI_SUCCESS;
+}
+
+int smpi_attr_delete(MPI_Comm comm, int keyval){
+ smpi_key_elem elem = xbt_dict_get_or_null(smpi_keyvals, (const char*)&keyval);
+ if(!elem)
+ return MPI_ERR_ARG;
+ if(elem->delete_fn!=MPI_NULL_DELETE_FN){
+ void * value;
+ int flag;
+ if(smpi_attr_get(comm, keyval, &value, &flag)==MPI_SUCCESS)
+ elem->delete_fn(comm, keyval, &value, &flag);
+ }
+ return smpi_comm_attr_delete(comm, keyval);;
+}
+
+int smpi_attr_get(MPI_Comm comm, int keyval, void* attr_value, int* flag){
+ smpi_key_elem elem = xbt_dict_get_or_null(smpi_keyvals, (const char*)&keyval);
+ if(!elem)
+ return MPI_ERR_ARG;
+ return smpi_comm_attr_get(comm, keyval, attr_value, flag);;
+}
+
+int smpi_attr_put(MPI_Comm comm, int keyval, void* attr_value){
+
+ if(!smpi_keyvals)
+ smpi_keyvals = xbt_dict_new();
+
+ smpi_key_elem elem = xbt_dict_get_or_null(smpi_keyvals, (const char*)&keyval);
+ if(!elem )
+ return MPI_ERR_ARG;
+ return smpi_comm_attr_put(comm, keyval, attr_value);;
+}
+