1 // -*- c++ -*-
2 //
3 // Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4 // University Research and Technology
5 // Corporation. All rights reserved.
6 // Copyright (c) 2004-2005 The University of Tennessee and The University
7 // of Tennessee Research Foundation. All rights
8 // reserved.
9 // Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10 // University of Stuttgart. All rights reserved.
11 // Copyright (c) 2004-2005 The Regents of the University of California.
12 // All rights reserved.
13 // Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved.
14 // Copyright (c) 2016 Los Alamos National Security, LLC. All rights
15 // reserved.
16 // $COPYRIGHT$
17 //
18 // Additional copyrights may follow
19 //
20 // $HEADER$
21 //
22
23 // do not include ompi_config.h because it kills the free/malloc defines
24 #include "mpi.h"
25 #include "ompi/constants.h"
26 #include "ompi/mpi/cxx/mpicxx.h"
27 #include "cxx_glue.h"
28
29
30 //
31 // These functions are all not inlined because they need to use locks to
32 // protect the handle maps and it would be bad to have those in headers
33 // because that would require that we always install the lock headers.
34 // Instead we take the function call hit (we're locking - who cares about
35 // a function call. And these aren't exactly the performance critical
36 // functions) and make everyone's life easier.
37 //
38
39
40 // construction
41 MPI::Comm::Comm()
42 {
43 }
44
45 // copy
46 MPI::Comm::Comm(const Comm_Null& data) : Comm_Null(data)
47 {
48 }
49
50 // This function needs some internal OMPI types, so it's not inlined
51 MPI::Errhandler
52 MPI::Comm::Create_errhandler(MPI::Comm::_MPI2CPP_ERRHANDLERFN_* function)
53 {
54 return ompi_cxx_errhandler_create_comm ((ompi_cxx_dummy_fn_t *) function);
55 }
56
57
58 //JGS I took the const out because it causes problems when trying to
59 //call this function with the predefined NULL_COPY_FN etc.
60 int
61 MPI::Comm::do_create_keyval(MPI_Comm_copy_attr_function* c_copy_fn,
62 MPI_Comm_delete_attr_function* c_delete_fn,
63 Copy_attr_function* cxx_copy_fn,
64 Delete_attr_function* cxx_delete_fn,
65 void* extra_state, int &keyval)
66 {
67 int ret, count = 0;
68 keyval_intercept_data_t *cxx_extra_state;
69
70 // If both the callbacks are C, then do the simple thing -- no
71 // need for all the C++ machinery.
72 if (NULL != c_copy_fn && NULL != c_delete_fn) {
73 ret = ompi_cxx_attr_create_keyval_comm (c_copy_fn, c_delete_fn, &keyval,
74 extra_state, 0, NULL);
75 if (MPI_SUCCESS != ret) {
76 return ompi_cxx_errhandler_invoke_comm(MPI_COMM_WORLD, ret,
77 "MPI::Comm::Create_keyval");
78 }
79 }
80
81 // If either callback is C++, then we have to use the C++
82 // callbacks for both, because we have to generate a new
83 // extra_state. And since we only get one extra_state (i.e., we
84 // don't get one extra_state for the copy callback and another
85 // extra_state for the delete callback), we have to use the C++
86 // callbacks for both (and therefore translate the C++-special
87 // extra_state into the user's original extra_state). Ensure to
88 // malloc() the struct here (vs new) so that it can be free()'ed
89 // by the C attribute base.
90 cxx_extra_state = (keyval_intercept_data_t*)
91 malloc(sizeof(keyval_intercept_data_t));
92 if (NULL == cxx_extra_state) {
93 return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, MPI_ERR_NO_MEM,
94 "MPI::Comm::Create_keyval");
95 }
96 cxx_extra_state->c_copy_fn = c_copy_fn;
97 cxx_extra_state->cxx_copy_fn = cxx_copy_fn;
98 cxx_extra_state->c_delete_fn = c_delete_fn;
99 cxx_extra_state->cxx_delete_fn = cxx_delete_fn;
100 cxx_extra_state->extra_state = extra_state;
101
102 // Error check. Must have exactly 2 non-NULL function pointers.
103 if (NULL != c_copy_fn) {
104 ++count;
105 }
106 if (NULL != c_delete_fn) {
107 ++count;
108 }
109 if (NULL != cxx_copy_fn) {
110 ++count;
111 }
112 if (NULL != cxx_delete_fn) {
113 ++count;
114 }
115 if (2 != count) {
116 free(cxx_extra_state);
117 return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, MPI_ERR_ARG,
118 "MPI::Comm::Create_keyval");
119 }
120
121 // We do not call MPI_Comm_create_keyval() here because we need to
122 // pass in the cxx_extra_state to the backend keyval creation so
123 // that when the keyval is destroyed (i.e., when its refcount goes
124 // to 0), the cxx_extra_state is free()'ed.
125 ret = ompi_cxx_attr_create_keyval_comm ((MPI_Comm_copy_attr_function *) ompi_mpi_cxx_comm_copy_attr_intercept,
126 ompi_mpi_cxx_comm_delete_attr_intercept,
127 &keyval, cxx_extra_state, 0, cxx_extra_state);
128 if (OMPI_SUCCESS != ret) {
129 return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, ret,
130 "MPI::Comm::Create_keyval");
131 }
132
133 return MPI_SUCCESS;
134 }
135