diff options
author | Quincey Koziol <koziol@koziol.gov> | 2019-03-11 22:29:14 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@koziol.gov> | 2019-03-11 22:29:14 (GMT) |
commit | 86598573641dfa27278c9e29df0fa79bd7d8e07f (patch) | |
tree | 449fbf063728fa602c311ec44ece4a4053bb24c8 /src | |
parent | 679b49d43d744f0cc34054944e827326f17a6f3d (diff) | |
download | hdf5-86598573641dfa27278c9e29df0fa79bd7d8e07f.zip hdf5-86598573641dfa27278c9e29df0fa79bd7d8e07f.tar.gz hdf5-86598573641dfa27278c9e29df0fa79bd7d8e07f.tar.bz2 |
Add API routines to retrieve, restore, reset, and free library state.
(Primarily for use in the async VOL connector, which has to schedule API
operations for future execution and then restore the state of the library when
the operation actually executes)
Diffstat (limited to 'src')
-rw-r--r-- | src/H5CX.c | 266 | ||||
-rw-r--r-- | src/H5CXprivate.h | 18 | ||||
-rw-r--r-- | src/H5VL.c | 159 | ||||
-rw-r--r-- | src/H5VLint.c | 368 | ||||
-rw-r--r-- | src/H5VLprivate.h | 14 | ||||
-rw-r--r-- | src/H5VLpublic.h | 4 |
6 files changed, 783 insertions, 46 deletions
@@ -64,17 +64,22 @@ #define H5CX_get_my_context() (&H5CX_head_g) #endif /* H5_HAVE_THREADSAFE */ +/* Common macro for the retrieving the pointer to a property list */ +#define H5CX_RETRIEVE_PLIST(PL, FAILVAL) \ + /* Check if the property list is already available */ \ + if(NULL == (*head)->ctx.PL) \ + /* Get the property list pointer */ \ + if(NULL == ((*head)->ctx.PL = (H5P_genplist_t *)H5I_object((*head)->ctx.H5_GLUE(PL,_id)))) \ + HGOTO_ERROR(H5E_CONTEXT, H5E_BADTYPE, (FAILVAL), "can't get property list") + /* Common macro for the duplicated code to retrieve properties from a property list */ #define H5CX_RETRIEVE_PROP_COMMON(PL, DEF_PL, PROP_NAME, PROP_FIELD) \ /* Check for default property list */ \ if((*head)->ctx.H5_GLUE(PL,_id) == (DEF_PL)) \ HDmemcpy(&(*head)->ctx.PROP_FIELD, &H5_GLUE3(H5CX_def_,PL,_cache).PROP_FIELD, sizeof(H5_GLUE3(H5CX_def_,PL,_cache).PROP_FIELD)); \ else { \ - /* Check if the property list is already available */ \ - if(NULL == (*head)->ctx.PL) \ - /* Get the dataset transfer property list pointer */ \ - if(NULL == ((*head)->ctx.PL = (H5P_genplist_t *)H5I_object((*head)->ctx.H5_GLUE(PL,_id)))) \ - HGOTO_ERROR(H5E_CONTEXT, H5E_BADTYPE, FAIL, "can't get default dataset transfer property list") \ + /* Retrieve the property list */ \ + H5CX_RETRIEVE_PLIST(PL, FAIL) \ \ /* Get the property */ \ if(H5P_get((*head)->ctx.PL, (PROP_NAME), &(*head)->ctx.PROP_FIELD) < 0) \ @@ -108,11 +113,8 @@ \ /* Check if property exists in DXPL */ \ if(!(*head)->ctx.H5_GLUE(PROP_FIELD,_set)) { \ - /* Check if the property list is already available */ \ - if(NULL == (*head)->ctx.dxpl) \ - /* Get the dataset transfer property list pointer */ \ - if(NULL == ((*head)->ctx.dxpl = (H5P_genplist_t *)H5I_object((*head)->ctx.dxpl_id))) \ - HGOTO_ERROR(H5E_CONTEXT, H5E_BADTYPE, FAIL, "can't get default dataset transfer property list") \ + /* Retrieve the dataset transfer property list */ \ + H5CX_RETRIEVE_PLIST(dxpl, FAIL) \ \ if((check_prop = H5P_exist_plist((*head)->ctx.dxpl, PROP_NAME)) < 0) \ HGOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, "error checking for property") \ @@ -129,15 +131,12 @@ /* Macro for the duplicated code to test and set properties for a property list */ #define H5CX_SET_PROP(PROP_NAME, PROP_FIELD) \ if((*head)->ctx.H5_GLUE(PROP_FIELD,_set)) { \ - /* Check if the property list is already available */ \ - if(NULL == (*head)->ctx.dxpl) \ - /* Get the dataset transfer property list pointer */ \ - if(NULL == ((*head)->ctx.dxpl = (H5P_genplist_t *)H5I_object((*head)->ctx.dxpl_id))) \ - HGOTO_ERROR(H5E_CONTEXT, H5E_BADTYPE, NULL, "can't get default dataset transfer property list") \ + /* Retrieve the dataset transfer property list */ \ + H5CX_RETRIEVE_PLIST(dxpl, NULL) \ \ - /* Set the chunk filter mask property */ \ + /* Set the property */ \ if(H5P_set((*head)->ctx.dxpl, PROP_NAME, &(*head)->ctx.PROP_FIELD) < 0) \ - HGOTO_ERROR(H5E_CONTEXT, H5E_CANTSET, NULL, "error setting filter mask xfer property") \ + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTSET, NULL, "error setting data xfer property") \ } /* end if */ #endif /* H5_HAVE_PARALLEL */ @@ -175,7 +174,7 @@ * corresponding property in the property list to be set when the API * context is popped, when returning from the API routine. Note that the * naming of these fields, <foo> and <foo>_set, is important for the -* H5CX_TEST_SET_PROP and H5CX_SET_PROP macros to work properly. + * H5CX_TEST_SET_PROP and H5CX_SET_PROP macros to work properly. */ typedef struct H5CX_t { /* DXPL */ @@ -378,6 +377,9 @@ static H5CX_dcpl_cache_t H5CX_def_dcpl_cache; /* Declare a static free list to manage H5CX_node_t structs */ H5FL_DEFINE_STATIC(H5CX_node_t); +/* Declare a static free list to manage H5CX_state_t structs */ +H5FL_DEFINE_STATIC(H5CX_state_t); + /*-------------------------------------------------------------------------- @@ -709,6 +711,226 @@ H5CX_push_special(void) /*------------------------------------------------------------------------- + * Function: H5CX_retrieve_state + * + * Purpose: Retrieve the state of an API context, for later resumption. + * + * Note: This routine _only_ tracks the state of API context information + * set before the VOL callback is invoked, not values that are + * set internal to the library. It's main purpose is to provide + * API context state to VOL connectors. + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: Quincey Koziol + * January 8, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5CX_retrieve_state(H5CX_state_t **api_state) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(head && *head); + HDassert(api_state); + + /* Allocate & clear API context state */ + if(NULL == (*api_state = H5FL_CALLOC(H5CX_state_t))) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTALLOC, FAIL, "unable to allocate new API context state") + + /* Check for non-default DXPL */ + if(H5P_DATASET_XFER_DEFAULT != (*head)->ctx.dxpl_id) { + /* Retrieve the DXPL property list */ + H5CX_RETRIEVE_PLIST(dxpl, FAIL) + + /* Copy the DXPL ID */ + if(((*api_state)->dxpl_id = H5P_copy_plist((H5P_genplist_t *)(*head)->ctx.dxpl, FALSE)) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTCOPY, FAIL, "can't copy property list") + } /* end if */ + else + (*api_state)->dxpl_id = H5P_DATASET_XFER_DEFAULT; + + /* Check for non-default LAPL */ + if(H5P_LINK_ACCESS_DEFAULT != (*head)->ctx.lapl_id) { + /* Retrieve the LAPL property list */ + H5CX_RETRIEVE_PLIST(lapl, FAIL) + + /* Copy the LAPL ID */ + if(((*api_state)->lapl_id = H5P_copy_plist((H5P_genplist_t *)(*head)->ctx.lapl, FALSE)) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTCOPY, FAIL, "can't copy property list") + } /* end if */ + else + (*api_state)->lapl_id = H5P_LINK_ACCESS_DEFAULT; + + /* Keep a reference to the current VOL wrapping context */ + (*api_state)->vol_wrap_ctx = (*head)->ctx.vol_wrap_ctx; + if(NULL != (*api_state)->vol_wrap_ctx) + if(H5VL_inc_vol_wrapper((*api_state)->vol_wrap_ctx) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTINC, FAIL, "can't increment refcount on VOL wrapping context") + + /* Keep a copy of the VOL connector property, if there is one */ + if((*head)->ctx.vol_connector_prop_valid && (*head)->ctx.vol_connector_prop.connector_id > 0) { + /* Get the connector property */ + HDmemcpy(&(*api_state)->vol_connector_prop, &(*head)->ctx.vol_connector_prop, sizeof(H5VL_connector_prop_t)); + + /* Check for actual VOL connector property */ + if((*api_state)->vol_connector_prop.connector_id) { + /* Copy connector info, if it exists */ + if((*api_state)->vol_connector_prop.connector_info) { + H5VL_class_t *connector; /* Pointer to connector */ + void *new_connector_info = NULL; /* Copy of connector info */ + + /* Retrieve the connector for the ID */ + if(NULL == (connector = (H5VL_class_t *)H5I_object((*api_state)->vol_connector_prop.connector_id))) + HGOTO_ERROR(H5E_CONTEXT, H5E_BADTYPE, FAIL, "not a VOL connector ID") + + /* Allocate and copy connector info */ + if(H5VL_copy_connector_info(connector, &new_connector_info, (*api_state)->vol_connector_prop.connector_info) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTCOPY, FAIL, "connector info copy failed") + (*api_state)->vol_connector_prop.connector_info = new_connector_info; + } /* end if */ + + /* Increment the refcount on the connector ID */ + if(H5I_inc_ref((*api_state)->vol_connector_prop.connector_id, FALSE) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTINC, FAIL, "incrementing VOL connector ID failed") + } /* end if */ + } /* end if */ + +#ifdef H5_HAVE_PARALLEL + /* Save parallel I/O settings */ + (*api_state)->coll_metadata_read = (*head)->ctx.coll_metadata_read; +#endif /* H5_HAVE_PARALLEL */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5CX_retrieve_state() */ + + +/*------------------------------------------------------------------------- + * Function: H5CX_restore_state + * + * Purpose: Restore an API context, from a previously retrieved state. + * + * Note: This routine _only_ resets the state of API context information + * set before the VOL callback is invoked, not values that are + * set internal to the library. It's main purpose is to restore + * API context state from VOL connectors. + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: Quincey Koziol + * January 9, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5CX_restore_state(const H5CX_state_t *api_state) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(head && *head); + HDassert(api_state); + + /* Restore the DXPL info */ + (*head)->ctx.dxpl_id = api_state->dxpl_id; + (*head)->ctx.dxpl = NULL; + + /* Restore the LAPL info */ + (*head)->ctx.lapl_id = api_state->lapl_id; + (*head)->ctx.lapl = NULL; + + /* Restore the VOL wrapper context */ + (*head)->ctx.vol_wrap_ctx = api_state->vol_wrap_ctx; + + /* Restore the VOL connector info */ + if(api_state->vol_connector_prop.connector_id) { + HDmemcpy(&(*head)->ctx.vol_connector_prop, &api_state->vol_connector_prop, sizeof(H5VL_connector_prop_t)); + (*head)->ctx.vol_connector_prop_valid = TRUE; + } /* end if */ + +#ifdef H5_HAVE_PARALLEL + /* Restore parallel I/O settings */ + (*head)->ctx.coll_metadata_read = api_state->coll_metadata_read; +#endif /* H5_HAVE_PARALLEL */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5CX_restore_state() */ + + +/*------------------------------------------------------------------------- + * Function: H5CX_free_state + * + * Purpose: Free a previously retrievedAPI context state + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: Quincey Koziol + * January 9, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5CX_free_state(H5CX_state_t *api_state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(api_state); + + /* Release the DXPL */ + if(api_state->dxpl_id != H5P_DATASET_XFER_DEFAULT) + if(H5I_dec_ref(api_state->dxpl_id) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTDEC, FAIL, "can't decrement refcount on DXPL") + + /* Release the LAPL */ + if(api_state->lapl_id != H5P_LINK_ACCESS_DEFAULT) + if(H5I_dec_ref(api_state->lapl_id) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTDEC, FAIL, "can't decrement refcount on LAPL") + + /* Release the VOL wrapper context */ + if(api_state->vol_wrap_ctx) + if(H5VL_dec_vol_wrapper(api_state->vol_wrap_ctx) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTDEC, FAIL, "can't decrement refcount on VOL wrapping context") + + /* Release the VOL connector property, if it was set */ + if(api_state->vol_connector_prop.connector_id) { + /* Clean up any VOL connector info */ + if(api_state->vol_connector_prop.connector_info) { + H5VL_class_t *connector; /* Pointer to connector */ + + /* Retrieve the connector for the ID */ + if(NULL == (connector = (H5VL_class_t *)H5I_object(api_state->vol_connector_prop.connector_id))) + HGOTO_ERROR(H5E_CONTEXT, H5E_BADTYPE, FAIL, "not a VOL connector ID") + + /* Free the connector info */ + if(H5VL_free_connector_info(connector, api_state->vol_connector_prop.connector_info) < 0) + HGOTO_ERROR(H5E_CONTEXT, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object") + } /* end if */ + + /* Decrement connector ID */ + if(H5I_dec_ref(api_state->vol_connector_prop.connector_id) < 0) + HDONE_ERROR(H5E_CONTEXT, H5E_CANTDEC, FAIL, "can't close VOL connector ID") + } /* end if */ + + /* Free the state */ + api_state = H5FL_FREE(H5CX_state_t, api_state); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5CX_free_state() */ + + +/*------------------------------------------------------------------------- * Function: H5CX_is_def_dxpl * * Purpose: Checks if the API context is using the library's default DXPL @@ -951,6 +1173,7 @@ H5CX_set_loc(hid_t #endif /* H5_HAVE_PARALLEL */ loc_id) { +#ifdef H5_HAVE_PARALLEL H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ herr_t ret_value = SUCCEED; /* Return value */ @@ -959,7 +1182,6 @@ H5CX_set_loc(hid_t /* Sanity check */ HDassert(head && *head); -#ifdef H5_HAVE_PARALLEL /* Set collective metadata read flag */ (*head)->ctx.coll_metadata_read = TRUE; @@ -980,10 +1202,14 @@ H5CX_set_loc(hid_t if(mpi_comm != MPI_COMM_NULL) MPI_Barrier(mpi_comm); } /* end if */ -#endif /* H5_HAVE_PARALLEL */ done: FUNC_LEAVE_NOAPI(ret_value) +#else /* H5_HAVE_PARALLEL */ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + FUNC_LEAVE_NOAPI(SUCCEED) +#endif /* H5_HAVE_PARALLEL */ } /* end H5CX_set_loc() */ diff --git a/src/H5CXprivate.h b/src/H5CXprivate.h index 51ee96b..80f1ac4 100644 --- a/src/H5CXprivate.h +++ b/src/H5CXprivate.h @@ -39,6 +39,19 @@ /* Library Private Typedefs */ /****************************/ +/* API context state */ +typedef struct H5CX_state_t { + hid_t dxpl_id; /* DXPL for operation */ + hid_t lapl_id; /* LAPL for operation */ + void *vol_wrap_ctx; /* VOL connector's "wrap context" for creating IDs */ + H5VL_connector_prop_t vol_connector_prop; /* VOL connector property */ + +#ifdef H5_HAVE_PARALLEL + /* Internal: Parallel I/O settings */ + hbool_t coll_metadata_read; /* Whether to use collective I/O for metadata read */ +#endif /* H5_HAVE_PARALLEL */ +} H5CX_state_t; + /*****************************/ /* Library-private Variables */ @@ -57,6 +70,11 @@ H5_DLL herr_t H5CX_pop(void); H5_DLL void H5CX_push_special(void); H5_DLL hbool_t H5CX_is_def_dxpl(void); +/* API context state routines */ +H5_DLL herr_t H5CX_retrieve_state(H5CX_state_t **api_state); +H5_DLL herr_t H5CX_restore_state(const H5CX_state_t *api_state); +H5_DLL herr_t H5CX_free_state(H5CX_state_t *api_state); + /* "Setter" routines for API context info */ H5_DLL void H5CX_set_dxpl(hid_t dxpl_id); H5_DLL void H5CX_set_lapl(hid_t lapl_id); @@ -488,6 +488,9 @@ done: * * Purpose: Compares two connector classes (based on their value field) * + * Note: This routine is _only_ for HDF5 VOL connector authors! It is + * _not_ part of the public API for HDF5 application developers. + * * Return: Success: Non-negative, *cmp set to a value like strcmp * * Failure: Negative, *cmp unset @@ -587,3 +590,159 @@ done: FUNC_LEAVE_API(ret_value) } /* H5VLobject() */ + +/*--------------------------------------------------------------------------- + * Function: H5VLretrieve_lib_state + * + * Purpose: Retrieves a copy of the internal state of the HDF5 library, + * so that it can be restored later. + * + * Note: This routine is _only_ for HDF5 VOL connector authors! It is + * _not_ part of the public API for HDF5 application developers. + * + * Return: Success: Non-negative, *state set + * Failure: Negative, *state unset + * + * Programmer: Quincey Koziol + * Thursday, January 10, 2019 + * + *--------------------------------------------------------------------------- + */ +herr_t +H5VLretrieve_lib_state(void **state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + /* Must use this, to avoid modifying the API context stack in FUNC_ENTER */ + FUNC_ENTER_API_NOINIT + H5TRACE1("e", "**x", state); + + /* Check args */ + if(NULL == state) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "invalid state pointer") + + /* Retrieve the library state */ + if(H5VL_retrieve_lib_state(state) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't retrieve library state") + +done: + FUNC_LEAVE_API_NOINIT(ret_value) +} /* H5VLretrieve_lib_state() */ + + +/*--------------------------------------------------------------------------- + * Function: H5VLrestore_lib_state + * + * Purpose: Restores the internal state of the HDF5 library. + * + * Note: This routine is _only_ for HDF5 VOL connector authors! It is + * _not_ part of the public API for HDF5 application developers. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, January 10, 2019 + * + *--------------------------------------------------------------------------- + */ +herr_t +H5VLrestore_lib_state(const void *state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + /* Must use this, to avoid modifying the API context stack in FUNC_ENTER */ + FUNC_ENTER_API_NOINIT + H5TRACE1("e", "*x", state); + + /* Check args */ + if(NULL == state) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "invalid state pointer") + + /* Restore the library state */ + if(H5VL_restore_lib_state(state) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't restore library state") + +done: + FUNC_LEAVE_API_NOINIT(ret_value) +} /* H5VLrestore_lib_state() */ + + +/*--------------------------------------------------------------------------- + * Function: H5VLreset_lib_state + * + * Purpose: Resets the internal state of the HDF5 library, undoing the + * affects of H5VLrestore_lib_state. + * + * Note: This routine is _only_ for HDF5 VOL connector authors! It is + * _not_ part of the public API for HDF5 application developers. + * + * Note: This routine must be called as a "pair" with + * H5VLrestore_lib_state. It can be called before / after / + * independently of H5VLfree_lib_state. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Saturday, February 23, 2019 + * + *--------------------------------------------------------------------------- + */ +herr_t +H5VLreset_lib_state(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + /* Must use this, to avoid modifying the API context stack in FUNC_ENTER */ + FUNC_ENTER_API_NOINIT + H5TRACE0("e",""); + + /* Reset the library state */ + if(H5VL_reset_lib_state() < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't reset library state") + +done: + FUNC_LEAVE_API_NOINIT(ret_value) +} /* H5VLreset_lib_state() */ + + +/*--------------------------------------------------------------------------- + * Function: H5VLfree_lib_state + * + * Purpose: Free a retrieved library state. + * + * Note: This routine is _only_ for HDF5 VOL connector authors! It is + * _not_ part of the public API for HDF5 application developers. + * + * Note: This routine must be called as a "pair" with + * H5VLretrieve_lib_state. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, January 10, 2019 + * + *--------------------------------------------------------------------------- + */ +herr_t +H5VLfree_lib_state(void *state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE1("e", "*x", state); + + /* Check args */ + if(NULL == state) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "invalid state pointer") + + /* Free the library state */ + if(H5VL_free_lib_state(state) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "can't free library state") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5VLfree_lib_state() */ + diff --git a/src/H5VLint.c b/src/H5VLint.c index 5aa25d2..7aeea02 100644 --- a/src/H5VLint.c +++ b/src/H5VLint.c @@ -51,7 +51,7 @@ /* Object wrapping context info */ typedef struct H5VL_wrap_ctx_t { unsigned rc; /* Ref. count for the # of times the context was set / reset */ - const H5VL_t *connector; /* VOL connector for "outermost" class to start wrap */ + H5VL_t *connector; /* VOL connector for "outermost" class to start wrap */ void *obj_wrap_ctx; /* "wrap context" for outermost connector */ } H5VL_wrap_ctx_t; @@ -68,7 +68,10 @@ static herr_t H5VL__free_cls(H5VL_class_t *cls); static void *H5VL__wrap_obj(void *obj, H5I_type_t obj_type); static H5VL_object_t *H5VL__new_vol_obj(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t wrap_obj); +static int64_t H5VL__conn_inc_rc(H5VL_t *connector); +static int64_t H5VL__conn_dec_rc(H5VL_t *connector); static void *H5VL__object(hid_t id, H5I_type_t obj_type); +static herr_t H5VL__free_vol_wrapper(H5VL_wrap_ctx_t *vol_wrap_ctx); /*********************/ @@ -317,7 +320,7 @@ H5VL__new_vol_obj(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t new_vol_obj->data = object; /* Bump the reference count on the VOL connector */ - vol_connector->nrefs++; + H5VL__conn_inc_rc(vol_connector); /* If this is a datatype, we have to hide the VOL object under the H5T_t pointer */ if(H5I_DATATYPE == type) { @@ -550,6 +553,76 @@ done: /*------------------------------------------------------------------------- + * Function: H5VL__conn_inc_rc + * + * Purpose: Wrapper to increment the ref. count on a connector. + * + * Return: Current ref. count (can't fail) + * + * Programmer: Quincey Koziol + * February 23, 2019 + * + *------------------------------------------------------------------------- + */ +static int64_t +H5VL__conn_inc_rc(H5VL_t *connector) +{ + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(connector); + + /* Increment refcount for connector */ + connector->nrefs++; + + FUNC_LEAVE_NOAPI(connector->nrefs) +} /* end H5VL__conn_inc_rc() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__conn_dec_rc + * + * Purpose: Wrapper to decrement the ref. count on a connector. + * + * Return: Current ref. count (>=0) on success, <0 on failure + * + * Programmer: Quincey Koziol + * February 23, 2019 + * + *------------------------------------------------------------------------- + */ +static int64_t +H5VL__conn_dec_rc(H5VL_t *connector) +{ + int64_t ret_value = -1; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check arguments */ + HDassert(connector); + + /* Decrement refcount for connector */ + connector->nrefs--; + + /* Check for last reference */ + if(0 == connector->nrefs) { + if(H5I_dec_ref(connector->id) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector") + H5FL_FREE(H5VL_t, connector); + + /* Set return value */ + ret_value = 0; + } /* end if */ + else + /* Set return value */ + ret_value = connector->nrefs; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__conn_dec_rc() */ + + +/*------------------------------------------------------------------------- * Function: H5VL_free_object * * Purpose: Wrapper to unregister an object ID with a VOL aux struct @@ -562,20 +635,16 @@ done: herr_t H5VL_free_object(H5VL_object_t *vol_obj) { - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(SUCCEED) + FUNC_ENTER_NOAPI(FAIL) /* Check arguments */ HDassert(vol_obj); - vol_obj->connector->nrefs --; - - if(0 == vol_obj->connector->nrefs) { - if(H5I_dec_ref(vol_obj->connector->id) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector") - vol_obj->connector = H5FL_FREE(H5VL_t, vol_obj->connector); - } /* end if */ + /* Decrement refcount on connector */ + if(H5VL__conn_dec_rc(vol_obj->connector) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector") vol_obj = H5FL_FREE(H5VL_object_t, vol_obj); @@ -952,6 +1021,189 @@ done: /*------------------------------------------------------------------------- + * Function: H5VL_retrieve_lib_state + * + * Purpose: Retrieve the state of the library. + * + * Note: Currently just retrieves the API context state, but could be + * expanded in the future. + * + * Return: Success: Non-negative, *state set + * Failure: Negative, *state unset + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_retrieve_lib_state(void **state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(state); + + /* Retrieve the API context state */ + if(H5CX_retrieve_state((H5CX_state_t **)state) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get API context state") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_retrieve_lib_state() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL_restore_lib_state + * + * Purpose: Restore the state of the library. + * + * Note: Currently just restores the API context state, but could be + * expanded in the future. + * + * Return: SUCCEED / FAIL + * + * Programmer: Quincey Koziol + * Thursday, January 10, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_restore_lib_state(const void *state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(state); + + /* Push a new API context on the stack */ + if(H5CX_push() < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't push API context") + + /* Restore the API context state */ + if(H5CX_restore_state((const H5CX_state_t *)state) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set API context state") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_restore_lib_state() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL_reset_lib_state + * + * Purpose: Reset the state of the library, undoing affects of + * H5VL_restore_lib_state. + * + * Note: Currently just resets the API context state, but could be + * expanded in the future. + * + * Note: This routine must be called as a "pair" with + * H5VL_restore_lib_state. It can be called before / after / + * independently of H5VL_free_lib_state. + * + * Return: SUCCEED / FAIL + * + * Programmer: Quincey Koziol + * Saturday, February 23, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_reset_lib_state(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Pop the API context off the stack */ + if(H5CX_pop() < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't pop API context") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_reset_lib_state() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL_free_lib_state + * + * Purpose: Free a library state. + * + * Note: This routine must be called as a "pair" with + * H5VL_retrieve_lib_state. + * + * Return: SUCCEED / FAIL + * + * Programmer: Quincey Koziol + * Thursday, January 10, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_free_lib_state(void *state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(state); + + /* Free the API context state */ + if(H5CX_free_state((H5CX_state_t *)state) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "can't free API context state") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_free_lib_state() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__free_vol_wrapper + * + * Purpose: Free object wrapping context for VOL connector + * + * Return: SUCCEED / FAIL + * + * Programmer: Quincey Koziol + * Wednesday, January 9, 2019 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5VL__free_vol_wrapper(H5VL_wrap_ctx_t *vol_wrap_ctx) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(vol_wrap_ctx); + HDassert(0 == vol_wrap_ctx->rc); + HDassert(vol_wrap_ctx->connector); + HDassert(vol_wrap_ctx->connector->cls); + + /* If there is a VOL connector object wrapping context, release it */ + if(vol_wrap_ctx->obj_wrap_ctx) + /* Release the VOL connector's object wrapping context */ + if((*vol_wrap_ctx->connector->cls->wrap_cls.free_wrap_ctx)(vol_wrap_ctx->obj_wrap_ctx) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release connector's object wrapping context") + + /* Decrement refcount on connector */ + if(H5VL__conn_dec_rc(vol_wrap_ctx->connector) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector") + + /* Release object wrapping context */ + H5FL_FREE(H5VL_wrap_ctx_t, vol_wrap_ctx); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__free_vol_wrapper() */ + + +/*------------------------------------------------------------------------- * Function: H5VL_set_vol_wrapper * * Purpose: Set up object wrapping context for current VOL connector @@ -961,7 +1213,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL_set_vol_wrapper(void *obj, const H5VL_t *connector) +H5VL_set_vol_wrapper(void *obj, H5VL_t *connector) { H5VL_wrap_ctx_t *vol_wrap_ctx = NULL; /* Object wrapping context */ void *obj_wrap_ctx = NULL; /* VOL connector's wrapping context */ @@ -993,8 +1245,11 @@ H5VL_set_vol_wrapper(void *obj, const H5VL_t *connector) if(NULL == (vol_wrap_ctx = H5FL_MALLOC(H5VL_wrap_ctx_t))) HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate VOL wrap context") + /* Increment the outstanding objects that are using the connector */ + H5VL__conn_inc_rc(connector); + /* Set up VOL object wrapper context */ - vol_wrap_ctx->rc = 1;; + vol_wrap_ctx->rc = 1; vol_wrap_ctx->connector = connector; vol_wrap_ctx->obj_wrap_ctx = obj_wrap_ctx; } /* end if */ @@ -1016,6 +1271,80 @@ done: /*------------------------------------------------------------------------- + * Function: H5VL_inc_vol_wrapper + * + * Purpose: Increment refcount on object wrapping context + * + * Return: SUCCEED / FAIL + * + * Programmer: Quincey Koziol + * Wednesday, January 9, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_inc_vol_wrapper(void *_vol_wrap_ctx) +{ + H5VL_wrap_ctx_t *vol_wrap_ctx = (H5VL_wrap_ctx_t *)_vol_wrap_ctx; /* VOL object wrapping context */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Check for valid, active VOL object wrap context */ + if(NULL == vol_wrap_ctx) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "no VOL object wrap context?") + if(0 == vol_wrap_ctx->rc) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "bad VOL object wrap context refcount?") + + /* Increment ref count on wrapping context */ + vol_wrap_ctx->rc++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_inc_vol_wrapper() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL_dec_vol_wrapper + * + * Purpose: Decrement refcount on object wrapping context, releasing it + * if the refcount drops to zero. + * + * Return: SUCCEED / FAIL + * + * Programmer: Quincey Koziol + * Wednesday, January 9, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_dec_vol_wrapper(void *_vol_wrap_ctx) +{ + H5VL_wrap_ctx_t *vol_wrap_ctx = (H5VL_wrap_ctx_t *)_vol_wrap_ctx; /* VOL object wrapping context */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Check for valid, active VOL object wrap context */ + if(NULL == vol_wrap_ctx) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "no VOL object wrap context?") + if(0 == vol_wrap_ctx->rc) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "bad VOL object wrap context refcount?") + + /* Decrement ref count on wrapping context */ + vol_wrap_ctx->rc--; + + /* Release context if the ref count drops to zero */ + if(0 == vol_wrap_ctx->rc) + if(H5VL__free_vol_wrapper(vol_wrap_ctx) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL object wrapping context") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_dec_vol_wrapper() */ + + +/*------------------------------------------------------------------------- * Function: H5VL_reset_vol_wrapper * * Purpose: Reset object wrapping context for current VOL connector @@ -1045,25 +1374,18 @@ H5VL_reset_vol_wrapper(void) /* Release context if the ref count drops to zero */ if(0 == vol_wrap_ctx->rc) { - /* If there is a VOL connector object wrapping context, release it */ - if(vol_wrap_ctx->obj_wrap_ctx) { - /* Release the VOL connector's object wrapping context */ - if((*vol_wrap_ctx->connector->cls->wrap_cls.free_wrap_ctx)(vol_wrap_ctx->obj_wrap_ctx) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release connector's object wrapping context") - } /* end if */ - /* Release object wrapping context */ - H5FL_FREE(H5VL_wrap_ctx_t, vol_wrap_ctx); + if(H5VL__free_vol_wrapper(vol_wrap_ctx) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL object wrapping context") /* Reset the wrapper context */ if(H5CX_set_vol_wrap_ctx(NULL) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL object wrap context") } /* end if */ - else { + else /* Save the updated wrapper context */ if(H5CX_set_vol_wrap_ctx(vol_wrap_ctx) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL object wrap context") - } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5VLprivate.h b/src/H5VLprivate.h index 283c77a..ac77ee0 100644 --- a/src/H5VLprivate.h +++ b/src/H5VLprivate.h @@ -41,8 +41,8 @@ typedef struct H5VL_object_t { /* Internal structure to hold the connector ID & info for FAPLs */ typedef struct H5VL_connector_prop_t { - hid_t connector_id; /* VOL connector's ID */ - const void *connector_info; /* VOL connector info, for open callbacks */ + hid_t connector_id; /* VOL connector's ID */ + void *connector_info; /* VOL connector info, for open callbacks */ } H5VL_connector_prop_t; /* Which kind of VOL connector field to use for searching */ @@ -92,11 +92,19 @@ H5_DLL herr_t H5VL_free_object(H5VL_object_t *obj); H5_DLL herr_t H5VL_get_wrap_ctx(const H5VL_class_t *connector, void *obj, void **wrap_ctx); H5_DLL herr_t H5VL_free_wrap_ctx(const H5VL_class_t *connector, void *wrap_ctx); -H5_DLL herr_t H5VL_set_vol_wrapper(void *obj, const H5VL_t *vol_connector); +H5_DLL herr_t H5VL_set_vol_wrapper(void *obj, H5VL_t *vol_connector); +H5_DLL herr_t H5VL_inc_vol_wrapper(void *vol_wrap_ctx); +H5_DLL herr_t H5VL_dec_vol_wrapper(void *vol_wrap_ctx); H5_DLL herr_t H5VL_reset_vol_wrapper(void); H5_DLL void * H5VL_wrap_object(const H5VL_class_t *connector, void *wrap_ctx, void *obj, H5I_type_t obj_type); +/* Library state functions */ +H5_DLL herr_t H5VL_retrieve_lib_state(void **state); +H5_DLL herr_t H5VL_restore_lib_state(const void *state); +H5_DLL herr_t H5VL_reset_lib_state(void); +H5_DLL herr_t H5VL_free_lib_state(void *state); + /* ID registration functions */ H5_DLL hid_t H5VL_register(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t app_ref); H5_DLL hid_t H5VL_wrap_register(H5I_type_t type, void *obj, hbool_t app_ref); diff --git a/src/H5VLpublic.h b/src/H5VLpublic.h index 72e69b8..cf6246b 100644 --- a/src/H5VLpublic.h +++ b/src/H5VLpublic.h @@ -450,6 +450,10 @@ H5_DLL herr_t H5VLunregister_connector(hid_t connector_id); H5_DLL herr_t H5VLcmp_connector_cls(int *cmp, hid_t connector_id1, hid_t connector_id2); H5_DLL hid_t H5VLwrap_register(void *obj, H5I_type_t type); H5_DLL void *H5VLobject(hid_t obj_id); +H5_DLL herr_t H5VLretrieve_lib_state(void **state); +H5_DLL herr_t H5VLrestore_lib_state(const void *state); +H5_DLL herr_t H5VLreset_lib_state(void); +H5_DLL herr_t H5VLfree_lib_state(void *state); /* Public wrappers for generic callbacks */ |