1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
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-2017 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) 2008-2009 Sun Microsystems, Inc.  All rights reserved.
14  * Copyright (c) 2009-2012 Cisco Systems, Inc.  All rights reserved.
15  * Copyright (c) 2015      Research Organization for Information Science
16  *                         and Technology (RIST). All rights reserved.
17  * Copyright (c) 2016      University of Houston. All rights reserved.
18  * Copyright (c) 2016-2017 IBM Corporation. All rights reserved.
19  * $COPYRIGHT$
20  *
21  * Additional copyrights may follow
22  *
23  * $HEADER$
24  */
25 
26 #include "ompi_config.h"
27 
28 #include "ompi/communicator/communicator.h"
29 #include "ompi/file/file.h"
30 #include "opal/class/opal_list.h"
31 #include "opal/util/output.h"
32 #include "ompi/runtime/params.h"
33 #include "ompi/mca/io/base/base.h"
34 #include "ompi/info/info.h"
35 
36 
37 opal_mutex_t ompi_mpi_file_bootstrap_mutex = OPAL_MUTEX_STATIC_INIT;
38 
39 
40 /*
41  * Table for Fortran <-> C file handle conversion
42  */
43 opal_pointer_array_t ompi_file_f_to_c_table = {{0}};
44 
45 /*
46  * MPI_FILE_NULL (_addr flavor is for F03 bindings)
47  */
48 ompi_predefined_file_t  ompi_mpi_file_null = {{{{0}}}};
49 ompi_predefined_file_t  *ompi_mpi_file_null_addr = &ompi_mpi_file_null;
50 
51 
52 /*
53  * Local functions
54  */
55 static void file_constructor(ompi_file_t *obj);
56 static void file_destructor(ompi_file_t *obj);
57 
58 
59 /*
60  * Class instance for ompi_file_t
61  */
62 OBJ_CLASS_INSTANCE(ompi_file_t,
63                    opal_infosubscriber_t,
64                    file_constructor,
65                    file_destructor);
66 
67 
68 /*
69  * Initialize file handling bookeeping
70  */
ompi_file_init(void)71 int ompi_file_init(void)
72 {
73     /* Setup file array */
74 
75     OBJ_CONSTRUCT(&ompi_file_f_to_c_table, opal_pointer_array_t);
76     if( OPAL_SUCCESS != opal_pointer_array_init(&ompi_file_f_to_c_table, 0,
77                                                 OMPI_FORTRAN_HANDLE_MAX, 16) ) {
78         return OMPI_ERROR;
79     }
80 
81     /* Setup MPI_FILE_NULL.  Note that it will have the default error
82        handler of MPI_ERRORS_RETURN, per MPI-2:9.7 (p265).  */
83 
84     OBJ_CONSTRUCT(&ompi_mpi_file_null.file, ompi_file_t);
85     ompi_mpi_file_null.file.f_comm = &ompi_mpi_comm_null.comm;
86     OBJ_RETAIN(ompi_mpi_file_null.file.f_comm);
87     ompi_mpi_file_null.file.f_f_to_c_index = 0;
88     opal_pointer_array_set_item(&ompi_file_f_to_c_table, 0,
89                                 &ompi_mpi_file_null.file);
90 
91     /* All done */
92 
93     return OMPI_SUCCESS;
94 }
95 
96 
97 /*
98  * Back end to MPI_FILE_OPEN
99  */
ompi_file_open(struct ompi_communicator_t * comm,const char * filename,int amode,struct opal_info_t * info,ompi_file_t ** fh)100 int ompi_file_open(struct ompi_communicator_t *comm, const char *filename,
101                    int amode, struct opal_info_t *info, ompi_file_t **fh)
102 {
103     int ret;
104     ompi_file_t *file;
105 
106     file = OBJ_NEW(ompi_file_t);
107     if (NULL == file) {
108         return OMPI_ERR_OUT_OF_RESOURCE;
109     }
110 
111 
112     /* Save the params */
113 
114     file->f_comm = comm;
115     OBJ_RETAIN(comm);
116 
117     /* Copy the info for the info layer */
118     file->super.s_info = OBJ_NEW(opal_info_t);
119     if (info) {
120         opal_info_dup(info, &(file->super.s_info));
121     }
122 
123     file->f_amode = amode;
124     file->f_filename = strdup(filename);
125     if (NULL == file->f_filename) {
126         OBJ_RELEASE(file);
127         return OMPI_ERR_OUT_OF_RESOURCE;
128     }
129 
130     /* Create the mutex */
131     OBJ_CONSTRUCT(&file->f_mutex, opal_mutex_t);
132 
133     /* Select a module and actually open the file */
134 
135     if (OMPI_SUCCESS != (ret = mca_io_base_file_select(file, NULL))) {
136         OBJ_RELEASE(file);
137         return ret;
138     }
139 
140     /* All done */
141 
142     *fh = file;
143     return OMPI_SUCCESS;
144 }
145 
146 
147 /*
148  * Back end to MPI_FILE_CLOSE.
149  */
ompi_file_close(ompi_file_t ** file)150 int ompi_file_close(ompi_file_t **file)
151 {
152 
153     OBJ_DESTRUCT(&(*file)->f_mutex);
154 
155     (*file)->f_flags |= OMPI_FILE_ISCLOSED;
156     OBJ_RELEASE(*file);
157     *file = &ompi_mpi_file_null.file;
158 
159     return OMPI_SUCCESS;
160 }
161 
162 
163 /*
164  * Shut down the MPI_File bookkeeping
165  */
ompi_file_finalize(void)166 int ompi_file_finalize(void)
167 {
168     int i, max;
169     size_t num_unnamed;
170     ompi_file_t *file;
171 
172     /* Release MPI_FILE_NULL.  Do this so that we don't get a bogus leak
173        report on it.  Plus, it's statically allocated, so we don't want
174      to call OBJ_RELEASE on it. */
175 
176     OBJ_DESTRUCT(&ompi_mpi_file_null.file);
177     opal_pointer_array_set_item(&ompi_file_f_to_c_table, 0, NULL);
178 
179     /* Iterate through all the file handles and destroy them.  Note
180        that this also takes care of destroying MPI_FILE_NULL. */
181 
182     max = opal_pointer_array_get_size(&ompi_file_f_to_c_table);
183     for (num_unnamed = i = 0; i < max; ++i) {
184         file = (ompi_file_t *)opal_pointer_array_get_item(&ompi_file_f_to_c_table, i);
185 
186         /* If the file was closed but still exists because the user
187            told us to never free handles, then do an OBJ_RELEASE it
188            and all is well.  Then get the value again and see if it's
189            actually been freed. */
190 
191         if (NULL != file && ompi_debug_no_free_handles &&
192             0 == (file->f_flags & OMPI_FILE_ISCLOSED)) {
193             OBJ_RELEASE(file);
194             file = (ompi_file_t *)opal_pointer_array_get_item(&ompi_file_f_to_c_table, i);
195         }
196 
197         if (NULL != file) {
198 
199             /* If the user wanted warnings about MPI object leaks,
200                print out a message */
201 
202             if (ompi_debug_show_handle_leaks) {
203                 ++num_unnamed;
204             }
205 
206             OBJ_RELEASE(file);
207         }
208         /* Don't bother setting each element back down to NULL; it
209            would just take a lot of thread locks / unlocks and since
210            we're destroying everything, it isn't worth it */
211     }
212     if (num_unnamed > 0) {
213         opal_output(0, "WARNING: %lu unnamed MPI_File handles still allocated at MPI_FINALIZE", (unsigned long)num_unnamed);
214     }
215     OBJ_DESTRUCT(&ompi_file_f_to_c_table);
216 
217     /* All done */
218 
219     return OMPI_SUCCESS;
220 }
221 
222 
223 /*
224  * Constructor
225  */
file_constructor(ompi_file_t * file)226 static void file_constructor(ompi_file_t *file)
227 {
228     /* Initialize the MPI_FILE_OPEN params */
229 
230     file->f_comm = NULL;
231     file->f_filename = NULL;
232     file->f_amode = 0;
233 
234     /* Initialize flags */
235 
236     file->f_flags = 0;
237 
238     /* Initialize the fortran <--> C translation index */
239 
240     file->f_f_to_c_index = opal_pointer_array_add(&ompi_file_f_to_c_table,
241                                                   file);
242 
243     /* Initialize the error handler.  Per MPI-2:9.7 (p265), the
244        default error handler on file handles is the error handler on
245        MPI_FILE_NULL, which starts out as MPI_ERRORS_RETURN (but can
246        be changed by invoking MPI_FILE_SET_ERRHANDLER on
247        MPI_FILE_NULL). */
248 
249     file->errhandler_type = OMPI_ERRHANDLER_TYPE_FILE;
250     if (file != &ompi_mpi_file_null.file) {
251         file->error_handler = ompi_mpi_file_null.file.error_handler;
252     } else {
253         file->error_handler = &ompi_mpi_errors_return.eh;
254     }
255     OBJ_RETAIN(file->error_handler);
256 
257     /* Initialize the module */
258 
259     file->f_io_version = MCA_IO_BASE_V_NONE;
260     memset(&(file->f_io_selected_module), 0,
261            sizeof(file->f_io_selected_module));
262     file->f_io_selected_data = NULL;
263 
264     /* If the user doesn't want us to ever free it, then add an extra
265        RETAIN here */
266 
267     if (ompi_debug_no_free_handles) {
268         OBJ_RETAIN(&(file->super));
269     }
270 }
271 
272 
273 /*
274  * Destructor
275  */
file_destructor(ompi_file_t * file)276 static void file_destructor(ompi_file_t *file)
277 {
278     /* Finalize the module */
279 
280     switch (file->f_io_version) {
281     case MCA_IO_BASE_V_2_0_0:
282         file->f_io_selected_module.v2_0_0.io_module_file_close(file);
283         break;
284     default:
285         /* Should never get here */
286         break;
287     }
288 
289     /* Finalize the data members */
290 
291     if (NULL != file->f_comm) {
292         OBJ_RELEASE(file->f_comm);
293 #if OPAL_ENABLE_DEBUG
294         file->f_comm = NULL;
295 #endif
296     }
297 
298     if (NULL != file->f_filename) {
299         free(file->f_filename);
300 #if OPAL_ENABLE_DEBUG
301         file->f_filename = NULL;
302 #endif
303     }
304 
305     if (NULL != file->error_handler) {
306         OBJ_RELEASE(file->error_handler);
307 #if OPAL_ENABLE_DEBUG
308         file->error_handler = NULL;
309 #endif
310     }
311 
312     if (NULL != file->super.s_info) {
313         OBJ_RELEASE(file->super.s_info);
314 #if OPAL_ENABLE_DEBUG
315         file->super.s_info = NULL;
316 #endif
317     }
318 
319     /* Reset the f_to_c table entry */
320 
321     if (MPI_UNDEFINED != file->f_f_to_c_index &&
322         NULL != opal_pointer_array_get_item(&ompi_file_f_to_c_table,
323                                             file->f_f_to_c_index)) {
324         opal_pointer_array_set_item(&ompi_file_f_to_c_table,
325                                     file->f_f_to_c_index, NULL);
326     }
327 }
328