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