1 // -*- c++ -*-
2 //
3 // Copyright (c) 2006-2016 Los Alamos National Security, LLC.  All rights
4 //                         reserved.
5 // Copyright (c) 2007-2008 Sun Microsystems, Inc.  All rights reserved.
6 // Copyright (c) 2007-2008 Cisco Systems, Inc.  All rights reserved.
7 // $COPYRIGHT$
8 //
9 // Additional copyrights may follow
10 //
11 // $HEADER$
12 //
13 
14 // do not include ompi_config.h because it kills the free/malloc defines
15 #include "mpi.h"
16 #include "ompi/mpi/cxx/mpicxx.h"
17 #include "ompi/constants.h"
18 #include "cxx_glue.h"
19 
20 void
Free()21 MPI::Datatype::Free()
22 {
23     (void)MPI_Type_free(&mpi_datatype);
24 }
25 
26 int
do_create_keyval(MPI_Type_copy_attr_function * c_copy_fn,MPI_Type_delete_attr_function * c_delete_fn,Copy_attr_function * cxx_copy_fn,Delete_attr_function * cxx_delete_fn,void * extra_state,int & keyval)27 MPI::Datatype::do_create_keyval(MPI_Type_copy_attr_function* c_copy_fn,
28                                 MPI_Type_delete_attr_function* c_delete_fn,
29                                 Copy_attr_function* cxx_copy_fn,
30                                 Delete_attr_function* cxx_delete_fn,
31                                 void* extra_state, int &keyval)
32 {
33     int ret, count = 0;
34     keyval_intercept_data_t *cxx_extra_state;
35 
36     // If both the callbacks are C, then do the simple thing -- no
37     // need for all the C++ machinery.
38     if (NULL != c_copy_fn && NULL != c_delete_fn) {
39         ret = ompi_cxx_attr_create_keyval_type (c_copy_fn, c_delete_fn, &keyval,
40                                                 extra_state, 0, NULL);
41         if (MPI_SUCCESS != ret) {
42             return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, ret,
43                                                     "MPI::Datatype::Create_keyval");
44         }
45     }
46 
47     // If either callback is C++, then we have to use the C++
48     // callbacks for both, because we have to generate a new
49     // extra_state.  And since we only get one extra_state (i.e., we
50     // don't get one extra_state for the copy callback and another
51     // extra_state for the delete callback), we have to use the C++
52     // callbacks for both (and therefore translate the C++-special
53     // extra_state into the user's original extra_state).
54     cxx_extra_state = (keyval_intercept_data_t *) malloc(sizeof(*cxx_extra_state));
55     if (NULL == cxx_extra_state) {
56         return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, MPI_ERR_NO_MEM,
57                                                 "MPI::Datatype::Create_keyval");
58     }
59 
60     cxx_extra_state->c_copy_fn = c_copy_fn;
61     cxx_extra_state->cxx_copy_fn = cxx_copy_fn;
62     cxx_extra_state->c_delete_fn = c_delete_fn;
63     cxx_extra_state->cxx_delete_fn = cxx_delete_fn;
64     cxx_extra_state->extra_state = extra_state;
65 
66     // Error check.  Must have exactly 2 non-NULL function pointers.
67     if (NULL != c_copy_fn) {
68         ++count;
69     }
70     if (NULL != c_delete_fn) {
71         ++count;
72     }
73     if (NULL != cxx_copy_fn) {
74         ++count;
75     }
76     if (NULL != cxx_delete_fn) {
77         ++count;
78     }
79     if (2 != count) {
80         free(cxx_extra_state);
81         return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, MPI_ERR_ARG,
82                                                 "MPI::Datatype::Create_keyval");
83     }
84 
85     // We do not call MPI_Datatype_create_keyval() here because we need to
86     // pass in a special destructor to the backend keyval creation
87     // that gets invoked when the keyval's reference count goes to 0
88     // and is finally destroyed (i.e., clean up some caching/lookup
89     // data here in the C++ bindings layer).  This destructor is
90     // *only* used in the C++ bindings, so it's not set by the C
91     // MPI_Comm_create_keyval().  Hence, we do all the work here (and
92     // ensure to set the destructor atomicly when the keyval is
93     // created).
94     ret = ompi_cxx_attr_create_keyval_type ((MPI_Type_copy_attr_function *) ompi_mpi_cxx_type_copy_attr_intercept,
95                                             ompi_mpi_cxx_type_delete_attr_intercept, &keyval,
96                                             cxx_extra_state, 0, NULL);
97     if (OMPI_SUCCESS != ret) {
98         return ompi_cxx_errhandler_invoke_comm (MPI_COMM_WORLD, ret,
99                                                 "MPI::Datatype::Create_keyval");
100     }
101 
102     return MPI_SUCCESS;
103 }
104