diff options
author | Neil Fortner <nfortne2@hdfgroup.org> | 2015-07-20 22:21:36 (GMT) |
---|---|---|
committer | Neil Fortner <nfortne2@hdfgroup.org> | 2015-07-20 22:21:36 (GMT) |
commit | f550bc0cea1da09002118fe8dc4455b18fc26717 (patch) | |
tree | c397791fb1b551b6965fda53da307c385d559081 /test/tskiplist.c | |
parent | 74e4cd4d2146b61b9d0179e5e1dc8c9048be2e19 (diff) | |
download | hdf5-f550bc0cea1da09002118fe8dc4455b18fc26717.zip hdf5-f550bc0cea1da09002118fe8dc4455b18fc26717.tar.gz hdf5-f550bc0cea1da09002118fe8dc4455b18fc26717.tar.bz2 |
[svn-r27415] Fix potential error with H5I_clear_type which could occur when a callback closed
a different ID in the same type. Added a new skiplist routine,
H5SL_try_free_safe, which iterates over items, freeing some of them, and which
intercepts and defers attempts to remove from the list outside of the main
iteration. Changed H5I_clear_type to use this function.
Tested: jam, koala, ostrich (h5committest); ummon
Diffstat (limited to 'test/tskiplist.c')
-rw-r--r-- | test/tskiplist.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/test/tskiplist.c b/test/tskiplist.c index 07e63fd..62c5f8e 100644 --- a/test/tskiplist.c +++ b/test/tskiplist.c @@ -1171,6 +1171,208 @@ test_skiplist_free(void) /**************************************************************** ** +** test_skiplist_try_free_safe(): Test H5SL (skip list) code. +** Tests 'try_free_safe' operation in skip lists. +** +****************************************************************/ +/* Macro definitions */ +#define TEST_TFS_MAX_NOBJS 100 +#define TEST_TFS_MIN_NOBJS 5 +#define TEST_TFS_NITER 50 + +/* Structure to hold the list of objects */ +typedef struct { + H5SL_t *slist; /* Skiplist holding the objects */ + struct test_tfs_obj_t *list; /* Linear list of objects */ + int nobjs; /* Number of objects in list */ + int nobjs_rem; /* Number of objects in list that have not been freed */ +} test_tfs_list_t; + +/* Structure for an object */ +typedef struct test_tfs_obj_t { + int idx; /* Index (key) for this object */ + int nfrees; /* Number of times this object has been freed */ +} test_tfs_obj_t; + +/* op_data struct for H5SL_iterate() */ +typedef struct test_tfs_it_ud_t { + test_tfs_list_t *obj_list; /* List of objects */ + int last_idx; /* Index of last object visited in iteration */ + int ncalls; /* Number of times this callback was called */ +} test_tfs_it_ud_t; + +/* iterate callback */ +static herr_t test_tfs_iter(void *_obj, void *key, void *_udata) { + test_tfs_obj_t *obj = (test_tfs_obj_t *)_obj; + test_tfs_it_ud_t *udata = (test_tfs_it_ud_t *)_udata; + + /* Check consistency */ + VERIFY((void *)&obj->idx, key, "obj->idx"); + VERIFY(obj, &udata->obj_list->list[obj->idx], "obj_list->list[obj->idx]"); + + /* Increment number of calls */ + udata->ncalls++; + + /* Verify we were given the correct object */ + do { + udata->last_idx++; + } while(udata->obj_list->list[udata->last_idx].nfrees != 0); + VERIFY(udata->last_idx, obj->idx, "H5SL_iterate"); + + return 0; +} /* end test_tfs_iter() */ + +/* try_free_safe callback */ +static htri_t test_tfs_free(void *_obj, void *key, void *_obj_list) { + test_tfs_obj_t *obj = (test_tfs_obj_t *)_obj; + test_tfs_list_t *obj_list = (test_tfs_list_t *)_obj_list; + test_tfs_it_ud_t iter_ud; + int nrems, rem_idx, i, j; + test_tfs_obj_t *obj_ret; + herr_t ret; /* return value */ + htri_t ret_value; + + /* Check consistency */ + VERIFY((void *)&obj->idx, key, "obj->idx"); + VERIFY(obj, &obj_list->list[obj->idx], "obj_list->list[obj->idx]"); + + /* Mark this object as freed (to make sure it isn't recursively freed, that + * is not something we support, we will undo this if we decide later not to + * free the object) */ + obj->nfrees++; + obj_list->nobjs_rem--; + + /* Decide how many objects to remove */ + nrems = (int)(HDrandom() % (long)3); + + /* Remove objects */ + for(i = 0; i < nrems; i++) + /* Check nobjs_rem */ + if(obj_list->nobjs_rem > 0) { + /* Remove a random object from the list */ + rem_idx = (int)(HDrandom() % (long)obj_list->nobjs_rem); + + /* Scan the list, finding the rem_idx'th object that has not been + * freed */ + for(j = 0; j < obj_list->nobjs; j++) + if(obj_list->list[j].nfrees == 0) { + if(rem_idx == 0) + break; + else + rem_idx--; + } /* end if */ + if(j == obj_list->nobjs) + ERROR("invalid obj_list"); + else { + /* Remove the object */ + obj_ret = (test_tfs_obj_t *)H5SL_remove(obj_list->slist, &j); + CHECK(obj_ret, NULL, "H5SL_remove"); + obj_ret->nfrees++; + obj_list->nobjs_rem--; + } /* end else */ + } /* end if */ + + /* Mark this object as not freed so we know to expect it in the iterate call + */ + obj->nfrees--; + obj_list->nobjs_rem++; + + /* Iterate over skip list (maybe) */ + if(HDrandom() % (long)5) { + iter_ud.obj_list = obj_list; + iter_ud.last_idx = -1; + iter_ud.ncalls = 0; + ret = H5SL_iterate(obj_list->slist, test_tfs_iter, &iter_ud); + CHECK(ret, FAIL, "H5SL_iterate"); + VERIFY(iter_ud.ncalls, obj_list->nobjs_rem, "H5SL_iterate"); + } /* end if */ + + /* Verify nobjs_rem is non-negative */ + if(obj_list->nobjs_rem < 0) + ERROR("invalid nobjs_rem"); + + /* Decide whether this object should be freed */ + if(HDrandom() % (long)2) { + /* Free the object */ + ret_value = TRUE; + obj->nfrees++; + obj_list->nobjs_rem--; + } /* end if */ + else + /* Do not free the object */ + ret_value = FALSE; + + return ret_value; +} /* end test_tfs_free() */ + +/* Test function */ +static void +test_skiplist_try_free_safe(void) +{ + test_tfs_list_t obj_list; + test_tfs_obj_t list[TEST_TFS_MAX_NOBJS]; + int i, j; + int nobjs_found; + hsize_t count; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(7, ("Testing Skip List 'Try Free Safe' Operation\n")); + + /* Create a skip list */ + obj_list.slist = H5SL_create(H5SL_TYPE_INT, NULL); + CHECK(obj_list.slist, NULL, "H5SL_create"); + + /* Init obj_list.list */ + obj_list.list = list; + for(j = 0; j < TEST_TFS_MAX_NOBJS; j++) + list[j].idx = j; + + for(i = 0; i < TEST_TFS_NITER; i++) { + /* Build object list */ + obj_list.nobjs = obj_list.nobjs_rem = (int)(TEST_TFS_MIN_NOBJS + (HDrandom() % (long)(TEST_TFS_MAX_NOBJS - TEST_TFS_MIN_NOBJS + 1))); + for(j = 0; j < obj_list.nobjs; j++) { + list[j].nfrees = 0; + ret = H5SL_insert(obj_list.slist, &list[j], &list[j].idx); + CHECK(ret, FAIL, "H5SL_insert"); + } /* end for */ + + /* Call H5S_try_free_safe() - free most of the items in the skip list in + * a safe manner */ + ret = H5SL_try_free_safe(obj_list.slist, test_tfs_free, &obj_list); + CHECK(ret, FAIL, "H5SL_try_free_safe"); + + /* Verify list */ + nobjs_found = 0; + for(j = 0; j < obj_list.nobjs; j++) + if(list[j].nfrees == 0) + nobjs_found++; + else + VERIFY(list[j].nfrees, (long)1, "list[j].nfrees"); + + /* Verify number of objects */ + VERIFY(obj_list.nobjs_rem, nobjs_found, "obj_list.nobjs_rem"); + count = H5SL_count(obj_list.slist); + VERIFY(count, (size_t)nobjs_found, "H5SL_count"); + + /* Release the skip list, forcibly freeing all nodes (will not make + * callbacks) */ + ret = H5SL_release(obj_list.slist); + CHECK(ret, FAIL, "H5SL_release"); + + /* Verify number of objects is 0 */ + count = H5SL_count(obj_list.slist); + VERIFY(count, (size_t)0, "H5SL_count"); + } /* end for */ + + /* Close the skip list */ + ret = H5SL_close(obj_list.slist); + CHECK(ret, FAIL, "H5SL_close"); + +} /* end test_skiplist_try_free_safe() */ + +/**************************************************************** +** ** test_skiplist_less(): Test H5SL (skip list) code. ** Tests 'less' operation in skip lists. ** @@ -1577,6 +1779,7 @@ test_skiplist(void) test_skiplist_add(); /* Test 'add' operation */ test_skiplist_destroy(); /* Test 'destroy' operation */ test_skiplist_free(); /* Test 'free' operation */ + test_skiplist_try_free_safe(); /* Test 'try_free_safe' operation */ test_skiplist_less(); /* Test 'less' operation */ test_skiplist_greater(); /* Test 'greater' operation */ test_skiplist_below(); /* Test 'below' operation */ |