1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /****************/
15 /* Module Setup */
16 /****************/
17
18
19 /***********/
20 /* Headers */
21 /***********/
22 #include "H5private.h" /* Generic Functions */
23 #include "H5ACprivate.h" /* Metadata cache */
24 #include "H5CXprivate.h" /* API Contexts */
25 #include "H5Dprivate.h" /* Datasets */
26 #include "H5Eprivate.h" /* Error handling */
27 #include "H5FLprivate.h" /* Free lists */
28 #include "H5FSprivate.h" /* File free space */
29 #include "H5Lprivate.h" /* Links */
30 #include "H5MMprivate.h" /* Memory management */
31 #include "H5Pprivate.h" /* Property lists */
32 #include "H5SLprivate.h" /* Skip lists */
33 #include "H5Tprivate.h" /* Datatypes */
34
35 /****************/
36 /* Local Macros */
37 /****************/
38
39
40 /******************/
41 /* Local Typedefs */
42 /******************/
43
44
45 /********************/
46 /* Package Typedefs */
47 /********************/
48
49
50 /********************/
51 /* Local Prototypes */
52 /********************/
53 static void H5_debug_mask(const char*);
54 #ifdef H5_HAVE_PARALLEL
55 static int H5_mpi_delete_cb(MPI_Comm comm, int keyval, void *attr_val, int *flag);
56 #endif /*H5_HAVE_PARALLEL*/
57
58 /*********************/
59 /* Package Variables */
60 /*********************/
61
62
63 /*****************************/
64 /* Library Private Variables */
65 /*****************************/
66
67 /* HDF5 API Entered variable */
68 /* (move to H5.c when new FUNC_ENTER macros in actual use -QAK) */
69 hbool_t H5_api_entered_g = FALSE;
70
71 /* statically initialize block for pthread_once call used in initializing */
72 /* the first global mutex */
73 #ifdef H5_HAVE_THREADSAFE
74 H5_api_t H5_g;
75 #else
76 hbool_t H5_libinit_g = FALSE; /* Library hasn't been initialized */
77 hbool_t H5_libterm_g = FALSE; /* Library isn't being shutdown */
78 #endif
79
80 #ifdef H5_HAVE_MPE
81 hbool_t H5_MPEinit_g = FALSE; /* MPE Library hasn't been initialized */
82 #endif
83
84 char H5_lib_vers_info_g[] = H5_VERS_INFO;
85 static hbool_t H5_dont_atexit_g = FALSE;
86 H5_debug_t H5_debug_g; /* debugging info */
87
88
89 /*******************/
90 /* Local Variables */
91 /*******************/
92
93
94 /*--------------------------------------------------------------------------
95 * NAME
96 * H5_init_library -- Initialize library-global information
97 * USAGE
98 * herr_t H5_init_library()
99 *
100 * RETURNS
101 * Non-negative on success/Negative on failure
102 *
103 * DESCRIPTION
104 * Initializes any library-global data or routines.
105 *
106 *--------------------------------------------------------------------------
107 */
108 herr_t
H5_init_library(void)109 H5_init_library(void)
110 {
111 herr_t ret_value = SUCCEED;
112
113 FUNC_ENTER_NOAPI(FAIL)
114
115 #ifdef H5_HAVE_PARALLEL
116 {
117 int mpi_initialized;
118 int mpi_finalized;
119 int mpi_code;
120
121 MPI_Initialized(&mpi_initialized);
122 MPI_Finalized(&mpi_finalized);
123
124 #ifdef H5_HAVE_MPE
125 /* Initialize MPE instrumentation library. */
126 if (!H5_MPEinit_g) {
127 int mpe_code;
128 if (mpi_initialized && !mpi_finalized) {
129 mpe_code = MPE_Init_log();
130 HDassert(mpe_code >=0);
131 H5_MPEinit_g = TRUE;
132 }
133 }
134 #endif /*H5_HAVE_MPE*/
135
136 /* add an attribute on MPI_COMM_SELF to call H5_term_library
137 when it is destroyed, i.e. on MPI_Finalize */
138 if (mpi_initialized && !mpi_finalized) {
139 int key_val;
140
141 if(MPI_SUCCESS != (mpi_code = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,
142 (MPI_Comm_delete_attr_function *)H5_mpi_delete_cb,
143 &key_val, NULL)))
144 HMPI_GOTO_ERROR(FAIL, "MPI_Comm_create_keyval failed", mpi_code)
145
146 if(MPI_SUCCESS != (mpi_code = MPI_Comm_set_attr(MPI_COMM_SELF, key_val, NULL)))
147 HMPI_GOTO_ERROR(FAIL, "MPI_Comm_set_attr failed", mpi_code)
148
149 if(MPI_SUCCESS != (mpi_code = MPI_Comm_free_keyval(&key_val)))
150 HMPI_GOTO_ERROR(FAIL, "MPI_Comm_free_keyval failed", mpi_code)
151 }
152 }
153 #endif /*H5_HAVE_PARALLEL*/
154
155 /*
156 * Make sure the package information is updated.
157 */
158 HDmemset(&H5_debug_g, 0, sizeof H5_debug_g);
159 H5_debug_g.pkg[H5_PKG_A].name = "a";
160 H5_debug_g.pkg[H5_PKG_AC].name = "ac";
161 H5_debug_g.pkg[H5_PKG_B].name = "b";
162 H5_debug_g.pkg[H5_PKG_D].name = "d";
163 H5_debug_g.pkg[H5_PKG_E].name = "e";
164 H5_debug_g.pkg[H5_PKG_F].name = "f";
165 H5_debug_g.pkg[H5_PKG_G].name = "g";
166 H5_debug_g.pkg[H5_PKG_HG].name = "hg";
167 H5_debug_g.pkg[H5_PKG_HL].name = "hl";
168 H5_debug_g.pkg[H5_PKG_I].name = "i";
169 H5_debug_g.pkg[H5_PKG_MF].name = "mf";
170 H5_debug_g.pkg[H5_PKG_MM].name = "mm";
171 H5_debug_g.pkg[H5_PKG_O].name = "o";
172 H5_debug_g.pkg[H5_PKG_P].name = "p";
173 H5_debug_g.pkg[H5_PKG_S].name = "s";
174 H5_debug_g.pkg[H5_PKG_T].name = "t";
175 H5_debug_g.pkg[H5_PKG_V].name = "v";
176 H5_debug_g.pkg[H5_PKG_Z].name = "z";
177
178 /*
179 * Install atexit() library cleanup routines unless the H5dont_atexit()
180 * has been called. Once we add something to the atexit() list it stays
181 * there permanently, so we set H5_dont_atexit_g after we add it to prevent
182 * adding it again later if the library is cosed and reopened.
183 */
184 if (!H5_dont_atexit_g) {
185
186 #if defined(H5_HAVE_THREADSAFE) && defined(H5_HAVE_WIN_THREADS)
187 /* Clean up Win32 thread resources. Pthreads automatically cleans up.
188 * This must be entered before the library cleanup code so it's
189 * executed in LIFO order (i.e., last).
190 */
191 (void)HDatexit(H5TS_win32_process_exit);
192 #endif /* H5_HAVE_THREADSAFE && H5_HAVE_WIN_THREADS */
193
194 /* Normal library termination code */
195 (void)HDatexit(H5_term_library);
196
197 H5_dont_atexit_g = TRUE;
198 } /* end if */
199
200 /*
201 * Initialize interfaces that might not be able to initialize themselves
202 * soon enough. The file & dataset interfaces must be initialized because
203 * calling H5P_create() might require the file/dataset property classes to be
204 * initialized. The property interface must be initialized before the file
205 * & dataset interfaces though, in order to provide them with the proper
206 * property classes.
207 * The link interface needs to be initialized so that link property lists
208 * have their properties registered.
209 * The FS module needs to be initialized as a result of the fix for HDFFV-10160:
210 * It might not be initialized during normal file open.
211 * When the application does not close the file, routines in the module might
212 * be called via H5_term_library() when shutting down the file.
213 */
214 if(H5E_init() < 0)
215 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize error interface")
216 if(H5P_init() < 0)
217 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize property list interface")
218 if(H5T_init() < 0)
219 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize datatype interface")
220 if(H5D_init() < 0)
221 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize dataset interface")
222 if(H5AC_init() < 0)
223 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize metadata caching interface")
224 if(H5L_init() < 0)
225 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize link interface")
226 if(H5FS_init() < 0)
227 HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize FS interface")
228
229 /* Debugging? */
230 H5_debug_mask("-all");
231 H5_debug_mask(HDgetenv("HDF5_DEBUG"));
232
233 done:
234 FUNC_LEAVE_NOAPI(ret_value)
235 } /* end H5_init_library() */
236
237
238 /*-------------------------------------------------------------------------
239 * Function: H5_term_library
240 *
241 * Purpose: Terminate interfaces in a well-defined order due to
242 * dependencies among the interfaces, then terminate
243 * library-specific data.
244 *
245 * Return: void
246 *
247 *-------------------------------------------------------------------------
248 */
249 void
H5_term_library(void)250 H5_term_library(void)
251 {
252 int pending, ntries = 0, n;
253 size_t at = 0;
254 char loop[1024];
255 H5E_auto2_t func;
256
257 #ifdef H5_HAVE_THREADSAFE
258 /* explicit locking of the API */
259 H5_FIRST_THREAD_INIT
260 H5_API_LOCK
261 #endif
262
263 /* Don't do anything if the library is already closed */
264 if(!(H5_INIT_GLOBAL))
265 goto done;
266
267 /* Indicate that the library is being shut down */
268 H5_TERM_GLOBAL = TRUE;
269
270 /* Push the API context without checking for errors */
271 H5CX_push_special();
272
273 /* Check if we should display error output */
274 (void)H5Eget_auto2(H5E_DEFAULT, &func, NULL);
275
276 /*
277 * Terminate each interface. The termination functions return a positive
278 * value if they do something that might affect some other interface in a
279 * way that would necessitate some cleanup work in the other interface.
280 */
281 #define DOWN(F) \
282 (((n = H5##F##_term_package()) && (at + 8) < sizeof loop)? \
283 (HDsprintf(loop + at, "%s%s", (at ? "," : ""), #F), \
284 at += HDstrlen(loop + at), \
285 n): \
286 ((n > 0 && (at + 5) < sizeof loop) ? \
287 (HDsprintf(loop + at, "..."), \
288 at += HDstrlen(loop + at), \
289 n) : n))
290
291 do {
292 pending = 0;
293
294 /* Try to organize these so the "higher" level components get shut
295 * down before "lower" level components that they might rely on. -QAK
296 */
297 pending += DOWN(L);
298
299 /* Close the "top" of various interfaces (IDs, etc) but don't shut
300 * down the whole interface yet, so that the object header messages
301 * get serialized correctly for entries in the metadata cache and the
302 * symbol table entry in the superblock gets serialized correctly, etc.
303 * all of which is performed in the 'F' shutdown.
304 */
305 pending += DOWN(A_top);
306 pending += DOWN(D_top);
307 pending += DOWN(G_top);
308 pending += DOWN(R_top);
309 pending += DOWN(S_top);
310 pending += DOWN(T_top);
311
312 /* Don't shut down the file code until objects in files are shut down */
313 if(pending == 0)
314 pending += DOWN(F);
315
316 /* Don't shut down the property list code until all objects that might
317 * use property lists are shut down */
318 if(pending == 0)
319 pending += DOWN(P);
320
321 /* Wait to shut down the "bottom" of various interfaces until the
322 * files are closed, so pieces of the file can be serialized
323 * correctly.
324 */
325 if(pending == 0) {
326 /* Shut down the "bottom" of the attribute, dataset, group,
327 * reference, dataspace, and datatype interfaces, fully closing
328 * out the interfaces now.
329 */
330 pending += DOWN(A);
331 pending += DOWN(D);
332 pending += DOWN(G);
333 pending += DOWN(R);
334 pending += DOWN(S);
335 pending += DOWN(T);
336 } /* end if */
337
338 /* Don't shut down "low-level" components until "high-level" components
339 * have successfully shut down. This prevents property lists and IDs
340 * from being closed "out from underneath" of the high-level objects
341 * that depend on them. -QAK
342 */
343 if(pending == 0) {
344 pending += DOWN(AC);
345 pending += DOWN(Z);
346 pending += DOWN(FD);
347 pending += DOWN(PL);
348 /* Don't shut down the error code until other APIs which use it are shut down */
349 if(pending == 0)
350 pending += DOWN(E);
351 /* Don't shut down the ID code until other APIs which use them are shut down */
352 if(pending == 0)
353 pending += DOWN(I);
354 /* Don't shut down the skip list code until everything that uses it is down */
355 if(pending == 0)
356 pending += DOWN(SL);
357 /* Don't shut down the free list code until everything that uses it is down */
358 if(pending == 0)
359 pending += DOWN(FL);
360 /* Don't shut down the API context code until _everything_ else is down */
361 if(pending == 0)
362 pending += DOWN(CX);
363 } /* end if */
364 } while(pending && ntries++ < 100);
365
366 if(pending) {
367 /* Only display the error message if the user is interested in them. */
368 if(func) {
369 HDfprintf(stderr, "HDF5: infinite loop closing library\n");
370 HDfprintf(stderr, " %s\n", loop);
371 #ifndef NDEBUG
372 HDabort();
373 #endif /* NDEBUG */
374 } /* end if */
375 } /* end if */
376
377 #ifdef H5_HAVE_MPE
378 /* Close MPE instrumentation library. May need to move this
379 * down if any of the below code involves using the instrumentation code.
380 */
381 if(H5_MPEinit_g) {
382 int mpi_initialized;
383 int mpi_finalized;
384 int mpe_code;
385
386 MPI_Initialized(&mpi_initialized);
387 MPI_Finalized(&mpi_finalized);
388
389 if (mpi_initialized && !mpi_finalized) {
390 mpe_code = MPE_Finish_log("h5log");
391 HDassert(mpe_code >=0);
392 } /* end if */
393 H5_MPEinit_g = FALSE; /* turn it off no matter what */
394 } /* end if */
395 #endif
396
397 /* Free open debugging streams */
398 while(H5_debug_g.open_stream) {
399 H5_debug_open_stream_t *tmp_open_stream;
400
401 tmp_open_stream = H5_debug_g.open_stream;
402 (void)HDfclose(H5_debug_g.open_stream->stream);
403 H5_debug_g.open_stream = H5_debug_g.open_stream->next;
404 (void)H5MM_free(tmp_open_stream);
405 } /* end while */
406
407 #if defined H5_MEMORY_ALLOC_SANITY_CHECK
408 /* Sanity check memory allocations */
409 H5MM_final_sanity_check();
410 #endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
411
412 /* Reset flag indicating that the library is being shut down */
413 H5_TERM_GLOBAL = FALSE;
414
415 /* Mark library as closed */
416 H5_INIT_GLOBAL = FALSE;
417
418 /* Don't pop the API context (i.e. H5CX_pop), since it's been shut down already */
419
420 done:
421 #ifdef H5_HAVE_THREADSAFE
422 H5_API_UNLOCK
423 #endif /* H5_HAVE_THREADSAFE */
424
425 return;
426 } /* end H5_term_library() */
427
428
429 /*-------------------------------------------------------------------------
430 * Function: H5dont_atexit
431 *
432 * Purpose: Indicates that the library is not to clean up after itself
433 * when the application exits by calling exit() or returning
434 * from main(). This function must be called before any other
435 * HDF5 function or constant is used or it will have no effect.
436 *
437 * If this function is used then certain memory buffers will not
438 * be de-allocated nor will open files be flushed automatically.
439 * The application may still call H5close() explicitly to
440 * accomplish these things.
441 *
442 * Return: Success: non-negative
443 *
444 * Failure: negative if this function is called more than
445 * once or if it is called too late.
446 *
447 *-------------------------------------------------------------------------
448 */
449 herr_t
H5dont_atexit(void)450 H5dont_atexit(void)
451 {
452 herr_t ret_value = SUCCEED; /* Return value */
453
454 FUNC_ENTER_API_NOINIT_NOERR_NOFS
455 H5TRACE0("e","");
456
457 if(H5_dont_atexit_g)
458 ret_value = FAIL;
459 else
460 H5_dont_atexit_g = TRUE;
461
462 FUNC_LEAVE_API_NOFS(ret_value)
463 } /* end H5dont_atexit() */
464
465
466 /*-------------------------------------------------------------------------
467 * Function: H5garbage_collect
468 *
469 * Purpose: Walks through all the garbage collection routines for the
470 * library, which are supposed to free any unused memory they have
471 * allocated.
472 *
473 * These should probably be registered dynamically in a linked list of
474 * functions to call, but there aren't that many right now, so we
475 * hard-wire them...
476 *
477 * Return: Success: non-negative
478 *
479 * Failure: negative
480 *
481 *-------------------------------------------------------------------------
482 */
483 herr_t
H5garbage_collect(void)484 H5garbage_collect(void)
485 {
486 herr_t ret_value = SUCCEED;
487
488 FUNC_ENTER_API(FAIL)
489 H5TRACE0("e","");
490
491 /* Call the garbage collection routines in the library */
492 if(H5FL_garbage_coll()<0)
493 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect objects")
494
495 done:
496 FUNC_LEAVE_API(ret_value)
497 } /* end H5garbage_collect() */
498
499
500 /*-------------------------------------------------------------------------
501 * Function: H5set_free_list_limits
502 *
503 * Purpose: Sets limits on the different kinds of free lists. Setting a value
504 * of -1 for a limit means no limit of that type. These limits are global
505 * for the entire library. Each "global" limit only applies to free lists
506 * of that type, so if an application sets a limit of 1 MB on each of the
507 * global lists, up to 3 MB of total storage might be allocated (1MB on
508 * each of regular, array and block type lists).
509 *
510 * The settings for block free lists are duplicated to factory free lists.
511 * Factory free list limits cannot be set independently currently.
512 *
513 * Parameters:
514 * int reg_global_lim; IN: The limit on all "regular" free list memory used
515 * int reg_list_lim; IN: The limit on memory used in each "regular" free list
516 * int arr_global_lim; IN: The limit on all "array" free list memory used
517 * int arr_list_lim; IN: The limit on memory used in each "array" free list
518 * int blk_global_lim; IN: The limit on all "block" free list memory used
519 * int blk_list_lim; IN: The limit on memory used in each "block" free list
520 *
521 * Return: Success: non-negative
522 *
523 * Failure: negative
524 *
525 *-------------------------------------------------------------------------
526 */
527 herr_t
H5set_free_list_limits(int reg_global_lim,int reg_list_lim,int arr_global_lim,int arr_list_lim,int blk_global_lim,int blk_list_lim)528 H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim,
529 int arr_list_lim, int blk_global_lim, int blk_list_lim)
530 {
531 herr_t ret_value = SUCCEED;
532
533 FUNC_ENTER_API(FAIL)
534 H5TRACE6("e", "IsIsIsIsIsIs", reg_global_lim, reg_list_lim, arr_global_lim,
535 arr_list_lim, blk_global_lim, blk_list_lim);
536
537 /* Call the free list function to actually set the limits */
538 if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim,
539 blk_global_lim, blk_list_lim, blk_global_lim, blk_list_lim)<0)
540 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "can't set garbage collection limits")
541
542 done:
543 FUNC_LEAVE_API(ret_value)
544 } /* end H5set_free_list_limits() */
545
546
547 /*-------------------------------------------------------------------------
548 * Function: H5_debug_mask
549 *
550 * Purpose: Set runtime debugging flags according to the string S. The
551 * string should contain file numbers and package names
552 * separated by other characters. A file number applies to all
553 * following package names up to the next file number. The
554 * initial file number is `2' (the standard error stream). Each
555 * package name can be preceded by a `+' or `-' to add or remove
556 * the package from the debugging list (`+' is the default). The
557 * special name `all' means all packages.
558 *
559 * The name `trace' indicates that API tracing is to be turned
560 * on or off.
561 *
562 * The name 'ttop' indicates that only top-level API calls
563 * should be shown. This also turns on tracing as if the
564 * 'trace' word was shown.
565 *
566 * Return: void
567 *
568 *-------------------------------------------------------------------------
569 */
570 static void
H5_debug_mask(const char * s)571 H5_debug_mask(const char *s)
572 {
573 FILE *stream = stderr;
574 char pkg_name[32], *rest;
575 size_t i;
576 hbool_t clear;
577
578 while (s && *s) {
579
580 if (HDisalpha(*s) || '-'==*s || '+'==*s) {
581
582 /* Enable or Disable debugging? */
583 if ('-'==*s) {
584 clear = TRUE;
585 s++;
586 } else if ('+'==*s) {
587 clear = FALSE;
588 s++;
589 } else {
590 clear = FALSE;
591 } /* end if */
592
593 /* Get the name */
594 for (i=0; HDisalpha(*s); i++, s++)
595 if (i<sizeof pkg_name)
596 pkg_name[i] = *s;
597 pkg_name[MIN(sizeof(pkg_name)-1, i)] = '\0';
598
599 /* Trace, all, or one? */
600 if (!HDstrcmp(pkg_name, "trace")) {
601 H5_debug_g.trace = clear ? NULL : stream;
602 } else if (!HDstrcmp(pkg_name, "ttop")) {
603 H5_debug_g.trace = stream;
604 H5_debug_g.ttop = (hbool_t)!clear;
605 } else if (!HDstrcmp(pkg_name, "ttimes")) {
606 H5_debug_g.trace = stream;
607 H5_debug_g.ttimes = (hbool_t)!clear;
608 } else if (!HDstrcmp(pkg_name, "all")) {
609 for (i=0; i<(size_t)H5_NPKGS; i++)
610 H5_debug_g.pkg[i].stream = clear ? NULL : stream;
611 } else {
612 for (i=0; i<(size_t)H5_NPKGS; i++) {
613 if (!HDstrcmp(H5_debug_g.pkg[i].name, pkg_name)) {
614 H5_debug_g.pkg[i].stream = clear ? NULL : stream;
615 break;
616 } /* end if */
617 } /* end for */
618 if (i>=(size_t)H5_NPKGS)
619 HDfprintf(stderr, "HDF5_DEBUG: ignored %s\n", pkg_name);
620 } /* end if-else */
621
622 } else if (HDisdigit(*s)) {
623 int fd = (int)HDstrtol(s, &rest, 0);
624 H5_debug_open_stream_t *open_stream;
625
626 if((stream = HDfdopen(fd, "w")) != NULL) {
627 (void)HDsetvbuf(stream, NULL, _IOLBF, (size_t)0);
628
629 if(NULL == (open_stream = (H5_debug_open_stream_t *)H5MM_malloc(sizeof(H5_debug_open_stream_t)))) {
630 (void)HDfclose(stream);
631 return;
632 } /* end if */
633
634 open_stream->stream = stream;
635 open_stream->next = H5_debug_g.open_stream;
636 H5_debug_g.open_stream = open_stream;
637 } /* end if */
638
639 s = rest;
640 } else {
641 s++;
642 } /* end if-else */
643 } /* end while */
644
645 return;
646
647 } /* end H5_debug_mask() */
648
649 #ifdef H5_HAVE_PARALLEL
650
651 /*-------------------------------------------------------------------------
652 * Function: H5_mpi_delete_cb
653 *
654 * Purpose: Callback attribute on MPI_COMM_SELF to terminate the HDF5
655 * library when the communicator is destroyed, i.e. on MPI_Finalize.
656 *
657 * Return: MPI_SUCCESS
658 *
659 *-------------------------------------------------------------------------
660 */
H5_mpi_delete_cb(MPI_Comm H5_ATTR_UNUSED comm,int H5_ATTR_UNUSED keyval,void H5_ATTR_UNUSED * attr_val,int H5_ATTR_UNUSED * flag)661 static int H5_mpi_delete_cb(MPI_Comm H5_ATTR_UNUSED comm, int H5_ATTR_UNUSED keyval, void H5_ATTR_UNUSED *attr_val, int H5_ATTR_UNUSED *flag)
662 {
663 H5_term_library();
664 return MPI_SUCCESS;
665 }
666 #endif /*H5_HAVE_PARALLEL*/
667
668
669 /*-------------------------------------------------------------------------
670 * Function: H5get_libversion
671 *
672 * Purpose: Returns the library version numbers through arguments. MAJNUM
673 * will be the major revision number of the library, MINNUM the
674 * minor revision number, and RELNUM the release revision number.
675 *
676 * Note: When printing an HDF5 version number it should be printed as
677 *
678 * printf("%u.%u.%u", maj, min, rel) or
679 * printf("version %u.%u release %u", maj, min, rel)
680 *
681 * Return: Non-negative on success/Negative on failure
682 *
683 *-------------------------------------------------------------------------
684 */
685 herr_t
H5get_libversion(unsigned * majnum,unsigned * minnum,unsigned * relnum)686 H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *relnum)
687 {
688 herr_t ret_value = SUCCEED;
689
690 FUNC_ENTER_API(FAIL)
691 H5TRACE3("e", "*Iu*Iu*Iu", majnum, minnum, relnum);
692
693 /* Set the version information */
694 if (majnum) *majnum = H5_VERS_MAJOR;
695 if (minnum) *minnum = H5_VERS_MINOR;
696 if (relnum) *relnum = H5_VERS_RELEASE;
697
698 done:
699 FUNC_LEAVE_API(ret_value)
700 } /* end H5get_libversion() */
701
702
703 /*-------------------------------------------------------------------------
704 * Function: H5check_version
705 *
706 * Purpose: Verifies that the arguments match the version numbers
707 * compiled into the library. This function is intended to be
708 * called from user to verify that the versions of header files
709 * compiled into the application match the version of the hdf5
710 * library.
711 *
712 * Return: Success: SUCCEED
713 *
714 * Failure: abort()
715 *
716 *-------------------------------------------------------------------------
717 */
718 #define VERSION_MISMATCH_WARNING \
719 "Warning! ***HDF5 library version mismatched error***\n" \
720 "The HDF5 header files used to compile this application do not match\n" \
721 "the version used by the HDF5 library to which this application is linked.\n" \
722 "Data corruption or segmentation faults may occur if the application continues.\n" \
723 "This can happen when an application was compiled by one version of HDF5 but\n" \
724 "linked with a different version of static or shared HDF5 library.\n" \
725 "You should recompile the application or check your shared library related\n" \
726 "settings such as 'LD_LIBRARY_PATH'.\n"
727
728 herr_t
H5check_version(unsigned majnum,unsigned minnum,unsigned relnum)729 H5check_version(unsigned majnum, unsigned minnum, unsigned relnum)
730 {
731 char lib_str[256];
732 char substr[] = H5_VERS_SUBRELEASE;
733 static int checked = 0; /* If we've already checked the version info */
734 static unsigned int disable_version_check = 0; /* Set if the version check should be disabled */
735 static const char *version_mismatch_warning = VERSION_MISMATCH_WARNING;
736 herr_t ret_value = SUCCEED; /* Return value */
737
738 FUNC_ENTER_API_NOINIT_NOERR_NOFS
739 H5TRACE3("e", "IuIuIu", majnum, minnum, relnum);
740
741 /* Don't check again, if we already have */
742 if (checked)
743 HGOTO_DONE(SUCCEED)
744
745 { const char *s; /* Environment string for disabling version check */
746
747 /* Allow different versions of the header files and library? */
748 s = HDgetenv ("HDF5_DISABLE_VERSION_CHECK");
749
750 if (s && HDisdigit(*s))
751 disable_version_check = (unsigned int)HDstrtol (s, NULL, 0);
752 }
753
754 if (H5_VERS_MAJOR!=majnum || H5_VERS_MINOR!=minnum ||
755 H5_VERS_RELEASE!=relnum) {
756 switch (disable_version_check) {
757 case 0:
758 HDfprintf(stderr, "%s%s", version_mismatch_warning,
759 "You can, at your own risk, disable this warning by setting the environment\n"
760 "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.\n"
761 "Setting it to 2 or higher will suppress the warning messages totally.\n");
762 /* Mention the versions we are referring to */
763 HDfprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n",
764 majnum, minnum, relnum,
765 (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE);
766 /* Show library settings if available */
767 HDfprintf (stderr, "%s", H5libhdf5_settings);
768
769 /* Bail out now. */
770 HDfputs ("Bye...\n", stderr);
771 HDabort ();
772 case 1:
773 /* continue with a warning */
774 /* Note that the warning message is embedded in the format string.*/
775 HDfprintf (stderr,
776 "%s'HDF5_DISABLE_VERSION_CHECK' "
777 "environment variable is set to %d, application will\n"
778 "continue at your own risk.\n",
779 version_mismatch_warning, disable_version_check);
780 /* Mention the versions we are referring to */
781 HDfprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n",
782 majnum, minnum, relnum,
783 (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE);
784 /* Show library settings if available */
785 HDfprintf (stderr, "%s", H5libhdf5_settings);
786 break;
787 default:
788 /* 2 or higher: continue silently */
789 break;
790 } /* end switch */
791
792 } /* end if */
793
794 /* Indicate that the version check has been performed */
795 checked = 1;
796
797 if (!disable_version_check){
798 /*
799 * Verify if H5_VERS_INFO is consistent with the other version information.
800 * Check only the first sizeof(lib_str) char. Assume the information
801 * will fit within this size or enough significance.
802 */
803 HDsnprintf(lib_str, sizeof(lib_str), "HDF5 library version: %d.%d.%d",
804 H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE);
805 if(*substr) {
806 HDstrncat(lib_str, "-", (size_t)1);
807 HDstrncat(lib_str, substr, (sizeof(lib_str) - HDstrlen(lib_str)) - 1);
808 } /* end if */
809 if (HDstrcmp(lib_str, H5_lib_vers_info_g)){
810 HDfputs ("Warning! Library version information error.\n"
811 "The HDF5 library version information are not "
812 "consistent in its source code.\nThis is NOT a fatal error "
813 "but should be corrected. Setting the environment\n"
814 "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of 1 "
815 "will suppress\nthis warning.\n",
816 stderr);
817 HDfprintf (stderr, "Library version information are:\n"
818 "H5_VERS_MAJOR=%d, H5_VERS_MINOR=%d, H5_VERS_RELEASE=%d, "
819 "H5_VERS_SUBRELEASE=%s,\nH5_VERS_INFO=%s\n",
820 H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE,
821 H5_VERS_SUBRELEASE, H5_VERS_INFO);
822 } /* end if */
823 }
824
825 done:
826 FUNC_LEAVE_API_NOFS(ret_value)
827 } /* end H5check_version() */
828
829
830 /*-------------------------------------------------------------------------
831 * Function: H5open
832 *
833 * Purpose: Initialize the library. This is normally called
834 * automatically, but if you find that an HDF5 library function
835 * is failing inexplicably, then try calling this function
836 * first.
837 *
838 * Return: Non-negative on success/Negative on failure
839 *
840 *-------------------------------------------------------------------------
841 */
842 herr_t
H5open(void)843 H5open(void)
844 {
845 herr_t ret_value=SUCCEED; /* Return value */
846
847 FUNC_ENTER_API_NOCLEAR(FAIL)
848 H5TRACE0("e","");
849 /* all work is done by FUNC_ENTER() */
850 done:
851 FUNC_LEAVE_API(ret_value)
852 } /* end H5open() */
853
854
855 /*-------------------------------------------------------------------------
856 * Function: H5close
857 *
858 * Purpose: Terminate the library and release all resources.
859 *
860 * Return: Non-negative on success/Negative on failure
861 *
862 *-------------------------------------------------------------------------
863 */
864 herr_t
H5close(void)865 H5close(void)
866 {
867 /*
868 * Don't call normal FUNC_ENTER() since we don't want to initialize the
869 * whole library just to release it all right away. It is safe to call
870 * this function for an uninitialized library.
871 */
872 FUNC_ENTER_API_NOINIT_NOERR_NOFS
873 H5TRACE0("e","");
874
875 H5_term_library();
876
877 FUNC_LEAVE_API_NOFS(SUCCEED)
878 } /* end H5close() */
879
880
881 /*-------------------------------------------------------------------------
882 * Function: H5allocate_memory
883 *
884 * Purpose: Allocate a memory buffer with the semantics of malloc().
885 *
886 * NOTE: This function is intended for use with filter
887 * plugins so that all allocation and free operations
888 * use the same memory allocator. It is not intended for
889 * use as a general memory allocator in applications.
890 *
891 * Parameters:
892 *
893 * size: The size of the buffer.
894 *
895 * clear: Whether or not to memset the buffer to 0.
896 *
897 * Return:
898 *
899 * Success: A pointer to the allocated buffer.
900 *
901 * Failure: NULL
902 *
903 *-------------------------------------------------------------------------
904 */
905 void *
H5allocate_memory(size_t size,hbool_t clear)906 H5allocate_memory(size_t size, hbool_t clear)
907 {
908 void *ret_value = NULL;
909
910 FUNC_ENTER_API_NOINIT
911 H5TRACE2("*x", "zb", size, clear);
912
913 if(clear)
914 ret_value = H5MM_calloc(size);
915 else
916 ret_value = H5MM_malloc(size);
917
918 FUNC_LEAVE_API_NOINIT(ret_value)
919 } /* end H5allocate_memory() */
920
921
922 /*-------------------------------------------------------------------------
923 * Function: H5resize_memory
924 *
925 * Purpose: Resize a memory buffer with the semantics of realloc().
926 *
927 * NOTE: This function is intended for use with filter
928 * plugins so that all allocation and free operations
929 * use the same memory allocator. It is not intended for
930 * use as a general memory allocator in applications.
931 *
932 * Parameters:
933 *
934 * mem: The buffer to be resized.
935 *
936 * size: The size of the buffer.
937 *
938 * Return:
939 *
940 * Success: A pointer to the resized buffer.
941 *
942 * Failure: NULL (the input buffer will be unchanged)
943 *
944 *-------------------------------------------------------------------------
945 */
946 void *
H5resize_memory(void * mem,size_t size)947 H5resize_memory(void *mem, size_t size)
948 {
949 void *ret_value = NULL;
950
951 FUNC_ENTER_API_NOINIT
952 H5TRACE2("*x", "*xz", mem, size);
953
954 ret_value = H5MM_realloc(mem, size);
955
956 FUNC_LEAVE_API_NOINIT(ret_value)
957 } /* end H5resize_memory() */
958
959
960 /*-------------------------------------------------------------------------
961 * Function: H5free_memory
962 *
963 * Purpose: Frees memory allocated by the library that it is the user's
964 * responsibility to free. Ensures that the same library
965 * that was used to allocate the memory frees it. Passing
966 * NULL pointers is allowed.
967 *
968 * Return: SUCCEED/FAIL
969 *
970 *-------------------------------------------------------------------------
971 */
972 herr_t
H5free_memory(void * mem)973 H5free_memory(void *mem)
974 {
975 FUNC_ENTER_API_NOINIT
976 H5TRACE1("e", "*x", mem);
977
978 /* At this time, it is impossible for this to fail. */
979 H5MM_xfree(mem);
980
981 FUNC_LEAVE_API_NOINIT(SUCCEED)
982 } /* end H5free_memory() */
983
984
985 /*-------------------------------------------------------------------------
986 * Function: H5is_library_threadsafe
987 *
988 * Purpose: Checks to see if the library was built with thread-safety
989 * enabled.
990 *
991 * Return: SUCCEED/FAIL
992 *
993 *-------------------------------------------------------------------------
994 */
995 herr_t
H5is_library_threadsafe(hbool_t * is_ts)996 H5is_library_threadsafe(hbool_t *is_ts)
997 {
998 FUNC_ENTER_API_NOINIT
999 H5TRACE1("e", "*b", is_ts);
1000
1001 HDassert(is_ts);
1002
1003 /* At this time, it is impossible for this to fail. */
1004 #ifdef H5_HAVE_THREADSAFE
1005 *is_ts = TRUE;
1006 #else /* H5_HAVE_THREADSAFE */
1007 *is_ts = FALSE;
1008 #endif /* H5_HAVE_THREADSAFE */
1009
1010 FUNC_LEAVE_API_NOINIT(SUCCEED)
1011 } /* end H5is_library_threadsafe() */
1012
1013
1014 #if defined(H5_HAVE_THREADSAFE) && defined(H5_BUILT_AS_DYNAMIC_LIB) \
1015 && defined(H5_HAVE_WIN32_API) && defined(H5_HAVE_WIN_THREADS)
1016 /*-------------------------------------------------------------------------
1017 * Function: DllMain
1018 *
1019 * Purpose: Handles various conditions in the library on Windows.
1020 *
1021 * NOTE: The main purpose of this is for handling Win32 thread cleanup
1022 * on thread/process detach.
1023 *
1024 * Only enabled when the shared Windows library is built with
1025 * thread safety enabled.
1026 *
1027 * Return: TRUE on success, FALSE on failure
1028 *
1029 *-------------------------------------------------------------------------
1030 */
1031 BOOL WINAPI
DllMain(_In_ HINSTANCE hinstDLL,_In_ DWORD fdwReason,_In_ LPVOID lpvReserved)1032 DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
1033 {
1034 /* Don't add our function enter/leave macros since this function will be
1035 * called before the library is initialized.
1036 *
1037 * NOTE: Do NOT call any CRT functions in DllMain!
1038 * This includes any functions that are called by from here!
1039 */
1040
1041 BOOL fOkay = TRUE;
1042
1043 switch(fdwReason)
1044 {
1045 case DLL_PROCESS_ATTACH:
1046 break;
1047
1048 case DLL_PROCESS_DETACH:
1049 break;
1050
1051 case DLL_THREAD_ATTACH:
1052 #ifdef H5_HAVE_WIN_THREADS
1053 if(H5TS_win32_thread_enter() < 0)
1054 fOkay = FALSE;
1055 #endif /* H5_HAVE_WIN_THREADS */
1056 break;
1057
1058 case DLL_THREAD_DETACH:
1059 #ifdef H5_HAVE_WIN_THREADS
1060 if(H5TS_win32_thread_exit() < 0)
1061 fOkay = FALSE;
1062 #endif /* H5_HAVE_WIN_THREADS */
1063 break;
1064
1065 default:
1066 /* Shouldn't get here */
1067 fOkay = FALSE;
1068 break;
1069 }
1070
1071 return fOkay;
1072 }
1073 #endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB && H5_HAVE_WIN_THREADS && H5_HAVE_THREADSAFE*/
1074
1075