1 /* Copyright (c) 2007-2017. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
7 #include "smpi_comm.hpp"
8 #include "smpi_coll.hpp"
9 #include "smpi_datatype_derived.hpp"
10 #include "smpi_op.hpp"
11 #include "smpi_process.hpp"
12 #include "smpi_win.hpp"
14 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(smpi_pmpi);
16 /* PMPI User level calls */
17 extern "C" { // Obviously, the C MPI interface should use the C linkage
19 int PMPI_Win_create( void *base, MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, MPI_Win *win){
22 if (comm == MPI_COMM_NULL) {
24 }else if ((base == nullptr && size != 0) || disp_unit <= 0 || size < 0 ){
25 retval= MPI_ERR_OTHER;
27 *win = new simgrid::smpi::Win( base, size, disp_unit, info, comm);
34 int PMPI_Win_allocate( MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, void *base, MPI_Win *win){
37 if (comm == MPI_COMM_NULL) {
39 }else if (disp_unit <= 0 || size < 0 ){
40 retval= MPI_ERR_OTHER;
42 void* ptr = xbt_malloc(size);
44 return MPI_ERR_NO_MEM;
45 *static_cast<void**>(base) = ptr;
46 *win = new simgrid::smpi::Win( ptr, size, disp_unit, info, comm,1);
53 int PMPI_Win_create_dynamic( MPI_Info info, MPI_Comm comm, MPI_Win *win){
56 if (comm == MPI_COMM_NULL) {
59 *win = new simgrid::smpi::Win(info, comm);
66 int PMPI_Win_attach(MPI_Win win, void *base, MPI_Aint size){
69 if(win == MPI_WIN_NULL){
71 } else if ((base == nullptr && size != 0) || size < 0 ){
72 retval= MPI_ERR_OTHER;
74 retval = win->attach(base, size);
80 int PMPI_Win_detach(MPI_Win win, void *base){
83 if(win == MPI_WIN_NULL){
85 } else if (base == nullptr){
86 retval= MPI_ERR_OTHER;
88 retval = win->detach(base);
95 int PMPI_Win_free( MPI_Win* win){
98 if (win == nullptr || *win == MPI_WIN_NULL) {
108 int PMPI_Win_set_name(MPI_Win win, char * name)
110 if (win == MPI_WIN_NULL) {
112 } else if (name == nullptr) {
120 int PMPI_Win_get_name(MPI_Win win, char * name, int* len)
122 if (win == MPI_WIN_NULL) {
124 } else if (name == nullptr) {
127 win->get_name(name, len);
132 int PMPI_Win_get_info(MPI_Win win, MPI_Info* info)
134 if (win == MPI_WIN_NULL) {
142 int PMPI_Win_set_info(MPI_Win win, MPI_Info info)
144 if (win == MPI_WIN_NULL) {
152 int PMPI_Win_get_group(MPI_Win win, MPI_Group * group){
153 if (win == MPI_WIN_NULL) {
156 win->get_group(group);
162 int PMPI_Win_fence( int assert, MPI_Win win){
165 if (win == MPI_WIN_NULL) {
166 retval = MPI_ERR_WIN;
168 int rank = smpi_process()->index();
169 TRACE_smpi_collective_in(rank, __FUNCTION__, nullptr);
170 retval = win->fence(assert);
171 TRACE_smpi_collective_out(rank, __FUNCTION__);
177 int PMPI_Get( void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,
178 MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win){
181 if (win == MPI_WIN_NULL) {
182 retval = MPI_ERR_WIN;
183 } else if (target_rank == MPI_PROC_NULL) {
184 retval = MPI_SUCCESS;
185 } else if (target_rank <0){
186 retval = MPI_ERR_RANK;
187 } else if (win->dynamic()==0 && target_disp <0){
188 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
189 retval = MPI_ERR_ARG;
190 } else if ((origin_count < 0 || target_count < 0) ||
191 (origin_addr==nullptr && origin_count > 0)){
192 retval = MPI_ERR_COUNT;
193 } else if ((not origin_datatype->is_valid()) || (not target_datatype->is_valid())) {
194 retval = MPI_ERR_TYPE;
196 int rank = smpi_process()->index();
198 win->get_group(&group);
199 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
201 retval = win->get( origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count,
204 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
210 int PMPI_Rget( void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,
211 MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win, MPI_Request* request){
214 if (win == MPI_WIN_NULL) {
215 retval = MPI_ERR_WIN;
216 } else if (target_rank == MPI_PROC_NULL) {
217 *request = MPI_REQUEST_NULL;
218 retval = MPI_SUCCESS;
219 } else if (target_rank <0){
220 retval = MPI_ERR_RANK;
221 } else if (win->dynamic()==0 && target_disp <0){
222 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
223 retval = MPI_ERR_ARG;
224 } else if ((origin_count < 0 || target_count < 0) ||
225 (origin_addr==nullptr && origin_count > 0)){
226 retval = MPI_ERR_COUNT;
227 } else if ((not origin_datatype->is_valid()) || (not target_datatype->is_valid())) {
228 retval = MPI_ERR_TYPE;
229 } else if(request == nullptr){
230 retval = MPI_ERR_REQUEST;
232 int rank = smpi_process()->index();
234 win->get_group(&group);
235 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
237 retval = win->get( origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count,
238 target_datatype, request);
240 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
246 int PMPI_Put( void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,
247 MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win){
250 if (win == MPI_WIN_NULL) {
251 retval = MPI_ERR_WIN;
252 } else if (target_rank == MPI_PROC_NULL) {
253 retval = MPI_SUCCESS;
254 } else if (target_rank <0){
255 retval = MPI_ERR_RANK;
256 } else if (win->dynamic()==0 && target_disp <0){
257 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
258 retval = MPI_ERR_ARG;
259 } else if ((origin_count < 0 || target_count < 0) ||
260 (origin_addr==nullptr && origin_count > 0)){
261 retval = MPI_ERR_COUNT;
262 } else if ((not origin_datatype->is_valid()) || (not target_datatype->is_valid())) {
263 retval = MPI_ERR_TYPE;
265 int rank = smpi_process()->index();
267 win->get_group(&group);
268 int dst_traced = group->index(target_rank);
269 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
270 TRACE_smpi_send(rank, rank, dst_traced, SMPI_RMA_TAG, origin_count*origin_datatype->size());
272 retval = win->put( origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count,
275 TRACE_smpi_ptp_out(rank, dst_traced, __FUNCTION__);
281 int PMPI_Rput( void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,
282 MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win, MPI_Request* request){
285 if (win == MPI_WIN_NULL) {
286 retval = MPI_ERR_WIN;
287 } else if (target_rank == MPI_PROC_NULL) {
288 *request = MPI_REQUEST_NULL;
289 retval = MPI_SUCCESS;
290 } else if (target_rank <0){
291 retval = MPI_ERR_RANK;
292 } else if (win->dynamic()==0 && target_disp <0){
293 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
294 retval = MPI_ERR_ARG;
295 } else if ((origin_count < 0 || target_count < 0) ||
296 (origin_addr==nullptr && origin_count > 0)){
297 retval = MPI_ERR_COUNT;
298 } else if ((not origin_datatype->is_valid()) || (not target_datatype->is_valid())) {
299 retval = MPI_ERR_TYPE;
300 } else if(request == nullptr){
301 retval = MPI_ERR_REQUEST;
303 int rank = smpi_process()->index();
305 win->get_group(&group);
306 int dst_traced = group->index(target_rank);
307 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
308 TRACE_smpi_send(rank, rank, dst_traced, SMPI_RMA_TAG, origin_count*origin_datatype->size());
310 retval = win->put( origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count,
311 target_datatype, request);
313 TRACE_smpi_ptp_out(rank, dst_traced, __FUNCTION__);
319 int PMPI_Accumulate( void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,
320 MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win){
323 if (win == MPI_WIN_NULL) {
324 retval = MPI_ERR_WIN;
325 } else if (target_rank == MPI_PROC_NULL) {
326 retval = MPI_SUCCESS;
327 } else if (target_rank <0){
328 retval = MPI_ERR_RANK;
329 } else if (win->dynamic()==0 && target_disp <0){
330 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
331 retval = MPI_ERR_ARG;
332 } else if ((origin_count < 0 || target_count < 0) ||
333 (origin_addr==nullptr && origin_count > 0)){
334 retval = MPI_ERR_COUNT;
335 } else if ((not origin_datatype->is_valid()) || (not target_datatype->is_valid())) {
336 retval = MPI_ERR_TYPE;
337 } else if (op == MPI_OP_NULL) {
340 int rank = smpi_process()->index();
342 win->get_group(&group);
343 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
344 retval = win->accumulate( origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count,
345 target_datatype, op);
347 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
353 int PMPI_Raccumulate( void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,
354 MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win, MPI_Request* request){
357 if (win == MPI_WIN_NULL) {
358 retval = MPI_ERR_WIN;
359 } else if (target_rank == MPI_PROC_NULL) {
360 *request = MPI_REQUEST_NULL;
361 retval = MPI_SUCCESS;
362 } else if (target_rank <0){
363 retval = MPI_ERR_RANK;
364 } else if (win->dynamic()==0 && target_disp <0){
365 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
366 retval = MPI_ERR_ARG;
367 } else if ((origin_count < 0 || target_count < 0) ||
368 (origin_addr==nullptr && origin_count > 0)){
369 retval = MPI_ERR_COUNT;
370 } else if ((not origin_datatype->is_valid()) || (not target_datatype->is_valid())) {
371 retval = MPI_ERR_TYPE;
372 } else if (op == MPI_OP_NULL) {
374 } else if(request == nullptr){
375 retval = MPI_ERR_REQUEST;
377 int rank = smpi_process()->index();
379 win->get_group(&group);
380 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
382 retval = win->accumulate( origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count,
383 target_datatype, op, request);
385 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
391 int PMPI_Get_accumulate(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, void *result_addr,
392 int result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, int target_count,
393 MPI_Datatype target_datatype, MPI_Op op, MPI_Win win){
396 if (win == MPI_WIN_NULL) {
397 retval = MPI_ERR_WIN;
398 } else if (target_rank == MPI_PROC_NULL) {
399 retval = MPI_SUCCESS;
400 } else if (target_rank <0){
401 retval = MPI_ERR_RANK;
402 } else if (win->dynamic()==0 && target_disp <0){
403 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
404 retval = MPI_ERR_ARG;
405 } else if ((origin_count < 0 || target_count < 0 || result_count <0) ||
406 (origin_addr==nullptr && origin_count > 0 && op != MPI_NO_OP) ||
407 (result_addr==nullptr && result_count > 0)){
408 retval = MPI_ERR_COUNT;
409 } else if ((origin_datatype != MPI_DATATYPE_NULL && not origin_datatype->is_valid()) ||
410 (not target_datatype->is_valid()) || (not result_datatype->is_valid())) {
411 retval = MPI_ERR_TYPE;
412 } else if (op == MPI_OP_NULL) {
415 int rank = smpi_process()->index();
417 win->get_group(&group);
418 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
420 retval = win->get_accumulate( origin_addr, origin_count, origin_datatype, result_addr,
421 result_count, result_datatype, target_rank, target_disp,
422 target_count, target_datatype, op);
424 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
431 int PMPI_Rget_accumulate(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, void *result_addr,
432 int result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, int target_count,
433 MPI_Datatype target_datatype, MPI_Op op, MPI_Win win, MPI_Request* request){
436 if (win == MPI_WIN_NULL) {
437 retval = MPI_ERR_WIN;
438 } else if (target_rank == MPI_PROC_NULL) {
439 *request = MPI_REQUEST_NULL;
440 retval = MPI_SUCCESS;
441 } else if (target_rank <0){
442 retval = MPI_ERR_RANK;
443 } else if (win->dynamic()==0 && target_disp <0){
444 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
445 retval = MPI_ERR_ARG;
446 } else if ((origin_count < 0 || target_count < 0 || result_count <0) ||
447 (origin_addr==nullptr && origin_count > 0 && op != MPI_NO_OP) ||
448 (result_addr==nullptr && result_count > 0)){
449 retval = MPI_ERR_COUNT;
450 } else if ((origin_datatype != MPI_DATATYPE_NULL && not origin_datatype->is_valid()) ||
451 (not target_datatype->is_valid()) || (not result_datatype->is_valid())) {
452 retval = MPI_ERR_TYPE;
453 } else if (op == MPI_OP_NULL) {
455 } else if(request == nullptr){
456 retval = MPI_ERR_REQUEST;
458 int rank = smpi_process()->index();
460 win->get_group(&group);
461 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
463 retval = win->get_accumulate( origin_addr, origin_count, origin_datatype, result_addr,
464 result_count, result_datatype, target_rank, target_disp,
465 target_count, target_datatype, op, request);
467 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
473 int PMPI_Fetch_and_op(void *origin_addr, void *result_addr, MPI_Datatype dtype, int target_rank, MPI_Aint target_disp, MPI_Op op, MPI_Win win){
474 return PMPI_Get_accumulate(origin_addr, origin_addr==nullptr?0:1, dtype, result_addr, 1, dtype, target_rank, target_disp, 1, dtype, op, win);
477 int PMPI_Compare_and_swap(void *origin_addr, void *compare_addr,
478 void *result_addr, MPI_Datatype datatype, int target_rank,
479 MPI_Aint target_disp, MPI_Win win){
482 if (win == MPI_WIN_NULL) {
483 retval = MPI_ERR_WIN;
484 } else if (target_rank == MPI_PROC_NULL) {
485 retval = MPI_SUCCESS;
486 } else if (target_rank <0){
487 retval = MPI_ERR_RANK;
488 } else if (win->dynamic()==0 && target_disp <0){
489 //in case of dynamic window, target_disp can be mistakenly seen as negative, as it is an address
490 retval = MPI_ERR_ARG;
491 } else if (origin_addr==nullptr || result_addr==nullptr || compare_addr==nullptr){
492 retval = MPI_ERR_COUNT;
493 } else if (not datatype->is_valid()) {
494 retval = MPI_ERR_TYPE;
496 int rank = smpi_process()->index();
498 win->get_group(&group);
499 TRACE_smpi_ptp_in(rank, __FUNCTION__, nullptr);
501 retval = win->compare_and_swap( origin_addr, compare_addr, result_addr, datatype,
502 target_rank, target_disp);
504 TRACE_smpi_ptp_out(rank, rank, __FUNCTION__);
510 int PMPI_Win_post(MPI_Group group, int assert, MPI_Win win){
513 if (win == MPI_WIN_NULL) {
514 retval = MPI_ERR_WIN;
515 } else if (group==MPI_GROUP_NULL){
516 retval = MPI_ERR_GROUP;
518 int rank = smpi_process()->index();
519 TRACE_smpi_collective_in(rank, __FUNCTION__, nullptr);
520 retval = win->post(group,assert);
521 TRACE_smpi_collective_out(rank, __FUNCTION__);
527 int PMPI_Win_start(MPI_Group group, int assert, MPI_Win win){
530 if (win == MPI_WIN_NULL) {
531 retval = MPI_ERR_WIN;
532 } else if (group==MPI_GROUP_NULL){
533 retval = MPI_ERR_GROUP;
535 int rank = smpi_process()->index();
536 TRACE_smpi_collective_in(rank, __FUNCTION__, nullptr);
537 retval = win->start(group,assert);
538 TRACE_smpi_collective_out(rank, __FUNCTION__);
544 int PMPI_Win_complete(MPI_Win win){
547 if (win == MPI_WIN_NULL) {
548 retval = MPI_ERR_WIN;
550 int rank = smpi_process()->index();
551 TRACE_smpi_collective_in(rank, __FUNCTION__, nullptr);
553 retval = win->complete();
555 TRACE_smpi_collective_out(rank, __FUNCTION__);
561 int PMPI_Win_wait(MPI_Win win){
564 if (win == MPI_WIN_NULL) {
565 retval = MPI_ERR_WIN;
567 int rank = smpi_process()->index();
568 TRACE_smpi_collective_in(rank, __FUNCTION__, nullptr);
570 retval = win->wait();
572 TRACE_smpi_collective_out(rank, __FUNCTION__);
578 int PMPI_Win_lock(int lock_type, int rank, int assert, MPI_Win win){
581 if (win == MPI_WIN_NULL) {
582 retval = MPI_ERR_WIN;
583 } else if (lock_type != MPI_LOCK_EXCLUSIVE &&
584 lock_type != MPI_LOCK_SHARED) {
585 retval = MPI_ERR_LOCKTYPE;
586 } else if (rank == MPI_PROC_NULL){
587 retval = MPI_SUCCESS;
589 int myrank = smpi_process()->index();
590 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
591 retval = win->lock(lock_type,rank,assert);
592 TRACE_smpi_collective_out(myrank, __FUNCTION__);
598 int PMPI_Win_unlock(int rank, MPI_Win win){
601 if (win == MPI_WIN_NULL) {
602 retval = MPI_ERR_WIN;
603 } else if (rank == MPI_PROC_NULL){
604 retval = MPI_SUCCESS;
606 int myrank = smpi_process()->index();
607 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
608 retval = win->unlock(rank);
609 TRACE_smpi_collective_out(myrank, __FUNCTION__);
615 int PMPI_Win_lock_all(int assert, MPI_Win win){
618 if (win == MPI_WIN_NULL) {
619 retval = MPI_ERR_WIN;
621 int myrank = smpi_process()->index();
622 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
623 retval = win->lock_all(assert);
624 TRACE_smpi_collective_out(myrank, __FUNCTION__);
630 int PMPI_Win_unlock_all(MPI_Win win){
633 if (win == MPI_WIN_NULL) {
634 retval = MPI_ERR_WIN;
636 int myrank = smpi_process()->index();
637 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
638 retval = win->unlock_all();
639 TRACE_smpi_collective_out(myrank, __FUNCTION__);
645 int PMPI_Win_flush(int rank, MPI_Win win){
648 if (win == MPI_WIN_NULL) {
649 retval = MPI_ERR_WIN;
650 } else if (rank == MPI_PROC_NULL){
651 retval = MPI_SUCCESS;
653 int myrank = smpi_process()->index();
654 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
655 retval = win->flush(rank);
656 TRACE_smpi_collective_out(myrank, __FUNCTION__);
662 int PMPI_Win_flush_local(int rank, MPI_Win win){
665 if (win == MPI_WIN_NULL) {
666 retval = MPI_ERR_WIN;
667 } else if (rank == MPI_PROC_NULL){
668 retval = MPI_SUCCESS;
670 int myrank = smpi_process()->index();
671 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
672 retval = win->flush_local(rank);
673 TRACE_smpi_collective_out(myrank, __FUNCTION__);
679 int PMPI_Win_flush_all(MPI_Win win){
682 if (win == MPI_WIN_NULL) {
683 retval = MPI_ERR_WIN;
685 int myrank = smpi_process()->index();
686 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
687 retval = win->flush_all();
688 TRACE_smpi_collective_out(myrank, __FUNCTION__);
694 int PMPI_Win_flush_local_all(MPI_Win win){
697 if (win == MPI_WIN_NULL) {
698 retval = MPI_ERR_WIN;
700 int myrank = smpi_process()->index();
701 TRACE_smpi_collective_in(myrank, __FUNCTION__, nullptr);
702 retval = win->flush_local_all();
703 TRACE_smpi_collective_out(myrank, __FUNCTION__);
710 int PMPI_Win_get_attr (MPI_Win win, int keyval, void *attribute_val, int* flag)
712 static MPI_Aint size;
713 static int disp_unit;
714 if (win==MPI_WIN_NULL)
719 *static_cast<void**>(attribute_val) = win->base();
724 *static_cast<MPI_Aint**>(attribute_val) = &size;
727 case MPI_WIN_DISP_UNIT :
728 disp_unit=win->disp_unit();
729 *static_cast<int**>(attribute_val) = &disp_unit;
733 return win->attr_get<simgrid::smpi::Win>(keyval, attribute_val, flag);
739 int PMPI_Win_set_attr (MPI_Win win, int type_keyval, void *attribute_val)
741 if (win==MPI_WIN_NULL)
744 return win->attr_put<simgrid::smpi::Win>(type_keyval, attribute_val);
747 int PMPI_Win_delete_attr (MPI_Win win, int type_keyval)
749 if (win==MPI_WIN_NULL)
752 return win->attr_delete<simgrid::smpi::Win>(type_keyval);
755 int PMPI_Win_create_keyval(MPI_Win_copy_attr_function* copy_fn, MPI_Win_delete_attr_function* delete_fn, int* keyval,
758 smpi_copy_fn _copy_fn={nullptr, nullptr, copy_fn};
759 smpi_delete_fn _delete_fn={nullptr, nullptr, delete_fn};
760 return simgrid::smpi::Keyval::keyval_create<simgrid::smpi::Win>(_copy_fn, _delete_fn, keyval, extra_state);
763 int PMPI_Win_free_keyval(int* keyval) {
764 return simgrid::smpi::Keyval::keyval_free<simgrid::smpi::Win>(keyval);
767 MPI_Win PMPI_Win_f2c(MPI_Fint win){
768 return static_cast<MPI_Win>(simgrid::smpi::Win::f2c(win));
771 MPI_Fint PMPI_Win_c2f(MPI_Win win){