mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-02-05 15:42:32 +08:00
Add H5atclose and H5is_library_terminating routines. (#139)
* Add H5atclose and H5is_library_terminating routines. * Add brief Doxygen comment for H5_atclose_func_t typedef. * Added /*out*/ flag to parameter list, for the tracing script. * Update doxygen comment for H5atclose with additional detail. * Return FAIL for H5is_library_threadsafe and H5is_library_terminating when their parameters are NULL.
This commit is contained in:
parent
436221cc18
commit
7950dca75c
125
src/H5.c
125
src/H5.c
@ -44,6 +44,13 @@
|
||||
/* Package Typedefs */
|
||||
/********************/
|
||||
|
||||
/* Node for list of 'atclose' routines to invoke at library shutdown */
|
||||
typedef struct H5_atclose_node_t {
|
||||
H5_atclose_func_t func; /* Function to invoke */
|
||||
void * ctx; /* Context to pass to function */
|
||||
struct H5_atclose_node_t *next; /* Pointer to next node in list */
|
||||
} H5_atclose_node_t;
|
||||
|
||||
/********************/
|
||||
/* Local Prototypes */
|
||||
/********************/
|
||||
@ -88,6 +95,12 @@ H5_debug_t H5_debug_g; /* debugging info */
|
||||
/* Local Variables */
|
||||
/*******************/
|
||||
|
||||
/* Linked list of registered 'atclose' functions to invoke at library shutdown */
|
||||
static H5_atclose_node_t *H5_atclose_head = NULL;
|
||||
|
||||
/* Declare a free list to manage the H5_atclose_node_t struct */
|
||||
H5FL_DEFINE_STATIC(H5_atclose_node_t);
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
NAME
|
||||
H5__init_package -- Initialize interface-specific information
|
||||
@ -305,6 +318,28 @@ H5_term_library(void)
|
||||
/* Check if we should display error output */
|
||||
(void)H5Eget_auto2(H5E_DEFAULT, &func, NULL);
|
||||
|
||||
/* Iterate over the list of 'atclose' callbacks that have been registered */
|
||||
if (H5_atclose_head) {
|
||||
H5_atclose_node_t *curr_atclose; /* Current 'atclose' node */
|
||||
|
||||
/* Iterate over all 'atclose' nodes, making callbacks */
|
||||
curr_atclose = H5_atclose_head;
|
||||
while (curr_atclose) {
|
||||
H5_atclose_node_t *tmp_atclose; /* Temporary pointer to 'atclose' node */
|
||||
|
||||
/* Invoke callback, providing context */
|
||||
(*curr_atclose->func)(curr_atclose->ctx);
|
||||
|
||||
/* Advance to next node and free this one */
|
||||
tmp_atclose = curr_atclose;
|
||||
curr_atclose = curr_atclose->next;
|
||||
H5FL_FREE(H5_atclose_node_t, tmp_atclose);
|
||||
} /* end while */
|
||||
|
||||
/* Reset list head, in case library is re-initialized */
|
||||
H5_atclose_head = NULL;
|
||||
} /* end if */
|
||||
|
||||
/*
|
||||
* Terminate each interface. The termination functions return a positive
|
||||
* value if they do something that might affect some other interface in a
|
||||
@ -970,6 +1005,45 @@ done:
|
||||
FUNC_LEAVE_API_NOPUSH(ret_value)
|
||||
} /* end H5open() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5atclose
|
||||
*
|
||||
* Purpose: Register a callback for the library to invoke when it's
|
||||
* closing. Callbacks are invoked in LIFO order.
|
||||
*
|
||||
* Return: Non-negative on success/Negative on failure
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
herr_t
|
||||
H5atclose(H5_atclose_func_t func, void *ctx)
|
||||
{
|
||||
H5_atclose_node_t *new_atclose; /* New 'atclose' node */
|
||||
herr_t ret_value = SUCCEED; /* Return value */
|
||||
|
||||
FUNC_ENTER_API(FAIL)
|
||||
H5TRACE2("e", "Hc*x", func, ctx);
|
||||
|
||||
/* Check arguments */
|
||||
if (NULL == func)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL func pointer")
|
||||
|
||||
/* Allocate space for the 'atclose' node */
|
||||
if (NULL == (new_atclose = H5FL_MALLOC(H5_atclose_node_t)))
|
||||
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate 'atclose' node")
|
||||
|
||||
/* Set up 'atclose' node */
|
||||
new_atclose->func = func;
|
||||
new_atclose->ctx = ctx;
|
||||
|
||||
/* Connector to linked-list of 'atclose' nodes */
|
||||
new_atclose->next = H5_atclose_head;
|
||||
H5_atclose_head = new_atclose;
|
||||
|
||||
done:
|
||||
FUNC_LEAVE_API(ret_value)
|
||||
} /* end H5atclose() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5close
|
||||
*
|
||||
@ -1107,23 +1181,58 @@ H5free_memory(void *mem)
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
herr_t
|
||||
H5is_library_threadsafe(hbool_t *is_ts)
|
||||
H5is_library_threadsafe(hbool_t *is_ts /*out*/)
|
||||
{
|
||||
herr_t ret_value = SUCCEED; /* Return value */
|
||||
|
||||
FUNC_ENTER_API_NOINIT
|
||||
H5TRACE1("e", "*b", is_ts);
|
||||
H5TRACE1("e", "x", is_ts);
|
||||
|
||||
HDassert(is_ts);
|
||||
|
||||
/* At this time, it is impossible for this to fail. */
|
||||
if(is_ts) {
|
||||
#ifdef H5_HAVE_THREADSAFE
|
||||
*is_ts = TRUE;
|
||||
*is_ts = TRUE;
|
||||
#else /* H5_HAVE_THREADSAFE */
|
||||
*is_ts = FALSE;
|
||||
*is_ts = FALSE;
|
||||
#endif /* H5_HAVE_THREADSAFE */
|
||||
}
|
||||
else
|
||||
ret_value = FAIL;
|
||||
|
||||
FUNC_LEAVE_API_NOINIT(SUCCEED)
|
||||
FUNC_LEAVE_API_NOINIT(ret_value)
|
||||
} /* end H5is_library_threadsafe() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5is_library_terminating
|
||||
*
|
||||
* Purpose: Checks to see if the library is shutting down.
|
||||
*
|
||||
* Note: Useful for plugins to detect when the library is terminating.
|
||||
* For example, a VOL connector could check if a "file close"
|
||||
* callback was the result of the library shutdown process, or
|
||||
* an API action from the application.
|
||||
*
|
||||
* Return: SUCCEED/FAIL
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
herr_t
|
||||
H5is_library_terminating(hbool_t *is_terminating /*out*/)
|
||||
{
|
||||
herr_t ret_value = SUCCEED; /* Return value */
|
||||
|
||||
FUNC_ENTER_API_NOINIT
|
||||
H5TRACE1("e", "x", is_terminating);
|
||||
|
||||
HDassert(is_terminating);
|
||||
|
||||
if(is_terminating)
|
||||
*is_terminating = H5_TERM_GLOBAL;
|
||||
else
|
||||
ret_value = FAIL;
|
||||
|
||||
FUNC_LEAVE_API_NOINIT(ret_value)
|
||||
} /* end H5is_library_terminating() */
|
||||
|
||||
#if defined(H5_HAVE_THREADSAFE) && defined(H5_BUILT_AS_DYNAMIC_LIB) && defined(H5_HAVE_WIN32_API) && \
|
||||
defined(H5_HAVE_WIN_THREADS)
|
||||
/*-------------------------------------------------------------------------
|
||||
|
@ -386,6 +386,11 @@ typedef struct H5_alloc_stats_t {
|
||||
size_t peak_alloc_blocks_count; /**< Peak # of blocks allocated */
|
||||
} H5_alloc_stats_t;
|
||||
|
||||
/**
|
||||
* Library shutdown callback, used by H5atclose().
|
||||
*/
|
||||
typedef void (*H5_atclose_func_t)(void *ctx);
|
||||
|
||||
/* Functions in H5.c */
|
||||
/**
|
||||
* \ingroup H5
|
||||
@ -403,6 +408,33 @@ typedef struct H5_alloc_stats_t {
|
||||
* it more than once.
|
||||
*/
|
||||
H5_DLL herr_t H5open(void);
|
||||
/**
|
||||
* \ingroup H5
|
||||
* \brief Registers a callback for the library to invoke when it's closing.
|
||||
* \param[in] func The function pointer to invoke
|
||||
* \param[in] ctx Context to pass to \p func when invoked
|
||||
* \return \herr_t
|
||||
*
|
||||
* \details H5atclose() registers a callback that the HDF5 library will invoke
|
||||
* when closing. The full capabilities of the HDF5 library are
|
||||
* available to callbacks invoked through this mechanism, library
|
||||
* shutdown will only begin in earnest when all callbacks have been
|
||||
* invoked and have returned.
|
||||
*
|
||||
* Registered callbacks are invoked in LIFO order, similar to the
|
||||
* Standard C 'atexit' routine. For example, if 'func1' is registered,
|
||||
* then 'func2', when the library is closing 'func2' will
|
||||
* be invoked first, then 'func1'.
|
||||
*
|
||||
* The \p ctx pointer will be passed to \p func when it's invoked.
|
||||
* NULL is allowed for \p ctx.
|
||||
*
|
||||
* If the HDF5 library is initialized and closed more than once, the
|
||||
* \p func callback must be registered within each open/close cycle.
|
||||
*
|
||||
* \since 1.12.1
|
||||
*/
|
||||
H5_DLL herr_t H5atclose(H5_atclose_func_t func, void *ctx);
|
||||
/**
|
||||
* \ingroup H5
|
||||
* \brief Flushes all data to disk, closes all open objects, and releases memory
|
||||
@ -611,6 +643,22 @@ H5_DLL herr_t H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *rel
|
||||
*
|
||||
*/
|
||||
H5_DLL herr_t H5check_version(unsigned majnum, unsigned minnum, unsigned relnum);
|
||||
/**
|
||||
* \ingroup H5
|
||||
* \brief Checks whether the HDF5 library is closing.
|
||||
* \param[out] is_terminating Flag indicating whether library is shutting down
|
||||
* \return \herr_t
|
||||
*
|
||||
* \details H5is_library_terminating() queries whether the HDF5 library is in
|
||||
* the process of shutting down. The \p is_terminating flag will only
|
||||
* be set to TRUE after shutdown starts, it will be FALSE before the
|
||||
* library has been initialized, while the library is initialized, and
|
||||
* after it has been closed. The value of \p is_terminating is
|
||||
* undefined if this routine fails.
|
||||
*
|
||||
* \since 1.12.1
|
||||
*/
|
||||
H5_DLL herr_t H5is_library_terminating(hbool_t *is_terminating);
|
||||
/**
|
||||
* \ingroup H5
|
||||
* \brief Determines whether the HDF5 library was built with the thread-safety
|
||||
|
114
test/tmisc.c
114
test/tmisc.c
@ -5752,6 +5752,119 @@ test_misc35(void)
|
||||
|
||||
} /* end test_misc35() */
|
||||
|
||||
/* Context to pass to 'atclose' callbacks */
|
||||
static int test_misc36_context;
|
||||
|
||||
/* 'atclose' callbacks for test_misc36 */
|
||||
static void
|
||||
test_misc36_cb1(void *_ctx)
|
||||
{
|
||||
int *ctx = (int *)_ctx; /* Set up context pointer */
|
||||
hbool_t is_terminating; /* Flag indicating the library is terminating */
|
||||
herr_t ret; /* Return value */
|
||||
|
||||
/* Check whether the library thinks it's terminating */
|
||||
is_terminating = FALSE;
|
||||
ret = H5is_library_terminating(&is_terminating);
|
||||
CHECK(ret, FAIL, "H5is_library_terminating");
|
||||
VERIFY(is_terminating, TRUE, "H5is_library_terminating");
|
||||
|
||||
/* Verify correct ordering for 'atclose' callbacks */
|
||||
if(0 != *ctx)
|
||||
HDabort();
|
||||
|
||||
/* Update context value */
|
||||
*ctx = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
test_misc36_cb2(void *_ctx)
|
||||
{
|
||||
int *ctx = (int *)_ctx; /* Set up context pointer */
|
||||
hbool_t is_terminating; /* Flag indicating the library is terminating */
|
||||
herr_t ret; /* Return value */
|
||||
|
||||
/* Check whether the library thinks it's terminating */
|
||||
is_terminating = FALSE;
|
||||
ret = H5is_library_terminating(&is_terminating);
|
||||
CHECK(ret, FAIL, "H5is_library_terminating");
|
||||
VERIFY(is_terminating, TRUE, "H5is_library_terminating");
|
||||
|
||||
/* Verify correct ordering for 'atclose' callbacks */
|
||||
if(1 != *ctx)
|
||||
HDabort();
|
||||
|
||||
/* Update context value */
|
||||
*ctx = 2;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
**
|
||||
** test_misc36(): Exercise H5atclose and H5is_library_terminating
|
||||
**
|
||||
****************************************************************/
|
||||
static void
|
||||
test_misc36(void)
|
||||
{
|
||||
hbool_t is_terminating; /* Flag indicating the library is terminating */
|
||||
herr_t ret; /* Return value */
|
||||
|
||||
/* Output message about test being performed */
|
||||
MESSAGE(5, ("H5atclose and H5is_library_terminating API calls"));
|
||||
|
||||
/* Check whether the library thinks it's terminating */
|
||||
is_terminating = TRUE;
|
||||
ret = H5is_library_terminating(&is_terminating);
|
||||
CHECK(ret, FAIL, "H5is_library_terminating");
|
||||
VERIFY(is_terminating, FALSE, "H5is_library_terminating");
|
||||
|
||||
/* Shut the library down */
|
||||
test_misc36_context = 0;
|
||||
H5close();
|
||||
|
||||
/* Check whether the library thinks it's terminating */
|
||||
is_terminating = TRUE;
|
||||
ret = H5is_library_terminating(&is_terminating);
|
||||
CHECK(ret, FAIL, "H5is_library_terminating");
|
||||
VERIFY(is_terminating, FALSE, "H5is_library_terminating");
|
||||
|
||||
/* Check the close context was not changed */
|
||||
VERIFY(test_misc36_context, 0, "H5atclose");
|
||||
|
||||
/* Restart the library */
|
||||
H5open();
|
||||
|
||||
/* Check whether the library thinks it's terminating */
|
||||
is_terminating = TRUE;
|
||||
ret = H5is_library_terminating(&is_terminating);
|
||||
CHECK(ret, FAIL, "H5is_library_terminating");
|
||||
VERIFY(is_terminating, FALSE, "H5is_library_terminating");
|
||||
|
||||
/* Register the 'atclose' callbacks */
|
||||
/* (Note that these will be called in reverse order, which is checked) */
|
||||
ret = H5atclose(&test_misc36_cb2, &test_misc36_context);
|
||||
CHECK(ret, FAIL, "H5atclose");
|
||||
ret = H5atclose(&test_misc36_cb1, &test_misc36_context);
|
||||
CHECK(ret, FAIL, "H5atclose");
|
||||
|
||||
/* Shut the library down */
|
||||
test_misc36_context = 0;
|
||||
H5close();
|
||||
|
||||
/* Check the close context was changed correctly */
|
||||
VERIFY(test_misc36_context, 2, "H5atclose");
|
||||
|
||||
/* Restart the library */
|
||||
H5open();
|
||||
|
||||
/* Close the library again */
|
||||
test_misc36_context = 0;
|
||||
H5close();
|
||||
|
||||
/* Check the close context was not changed */
|
||||
VERIFY(test_misc36_context, 0, "H5atclose");
|
||||
} /* end test_misc36() */
|
||||
|
||||
/****************************************************************
|
||||
**
|
||||
** test_misc(): Main misc. test routine.
|
||||
@ -5803,6 +5916,7 @@ test_misc(void)
|
||||
test_misc33(); /* Test to verify that H5HL_offset_into() returns error if offset exceeds heap block */
|
||||
test_misc34(); /* Test behavior of 0 and NULL in H5MM API calls */
|
||||
test_misc35(); /* Test behavior of free-list & allocation statistics API calls */
|
||||
test_misc36(); /* Exercise H5atclose and H5is_library_terminating */
|
||||
|
||||
} /* test_misc() */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user