|
0 |
Description: Merge upstream fix for issue HDFFV-8917
|
|
1 |
Changeset from upstream SVN r25681 (branches/hdf5_1_8).
|
|
2 |
Index: hdf5/src/H5T.c
|
|
3 |
===================================================================
|
|
4 |
--- hdf5.orig/src/H5T.c
|
|
5 |
+++ hdf5/src/H5T.c
|
|
6 |
@@ -529,7 +529,7 @@ H5FL_DEFINE_STATIC(H5T_path_t);
|
|
7 |
/* Datatype ID class */
|
|
8 |
static const H5I_class_t H5I_DATATYPE_CLS[1] = {{
|
|
9 |
H5I_DATATYPE, /* ID class value */
|
|
10 |
- 0, /* Class flags */
|
|
11 |
+ H5I_CLASS_REUSE_IDS, /* Class flags */
|
|
12 |
8, /* # of reserved IDs for class */
|
|
13 |
(H5I_free_t)H5T_close /* Callback routine for closing objects of this class */
|
|
14 |
}};
|
|
15 |
Index: hdf5/src/H5E.c
|
|
16 |
===================================================================
|
|
17 |
--- hdf5.orig/src/H5E.c
|
|
18 |
+++ hdf5/src/H5E.c
|
|
19 |
@@ -122,7 +122,7 @@ H5FL_DEFINE_STATIC(H5E_msg_t);
|
|
20 |
/* Error class ID class */
|
|
21 |
static const H5I_class_t H5I_ERRCLS_CLS[1] = {{
|
|
22 |
H5I_ERROR_CLASS, /* ID class value */
|
|
23 |
- 0, /* Class flags */
|
|
24 |
+ H5I_CLASS_REUSE_IDS, /* Class flags */
|
|
25 |
0, /* # of reserved IDs for class */
|
|
26 |
(H5I_free_t)H5E_unregister_class /* Callback routine for closing objects of this class */
|
|
27 |
}};
|
|
28 |
@@ -130,7 +130,7 @@ static const H5I_class_t H5I_ERRCLS_CLS[
|
|
29 |
/* Error message ID class */
|
|
30 |
static const H5I_class_t H5I_ERRMSG_CLS[1] = {{
|
|
31 |
H5I_ERROR_MSG, /* ID class value */
|
|
32 |
- 0, /* Class flags */
|
|
33 |
+ H5I_CLASS_REUSE_IDS, /* Class flags */
|
|
34 |
0, /* # of reserved IDs for class */
|
|
35 |
(H5I_free_t)H5E_close_msg /* Callback routine for closing objects of this class */
|
|
36 |
}};
|
|
37 |
@@ -138,7 +138,7 @@ static const H5I_class_t H5I_ERRMSG_CLS[
|
|
38 |
/* Error stack ID class */
|
|
39 |
static const H5I_class_t H5I_ERRSTK_CLS[1] = {{
|
|
40 |
H5I_ERROR_STACK, /* ID class value */
|
|
41 |
- 0, /* Class flags */
|
|
42 |
+ H5I_CLASS_REUSE_IDS, /* Class flags */
|
|
43 |
0, /* # of reserved IDs for class */
|
|
44 |
(H5I_free_t)H5E_close_stack /* Callback routine for closing objects of this class */
|
|
45 |
}};
|
|
46 |
Index: hdf5/src/H5I.c
|
|
47 |
===================================================================
|
|
48 |
--- hdf5.orig/src/H5I.c
|
|
49 |
+++ hdf5/src/H5I.c
|
|
50 |
@@ -814,7 +814,7 @@ H5I__wrapped_cb(void *_item, void UNUSED
|
|
51 |
HDassert(udata);
|
|
52 |
|
|
53 |
/* Break out if we see a free ID */
|
|
54 |
- if(udata->nextid != item->id) {
|
|
55 |
+ if(udata->nextid != (ID_MASK & item->id)) {
|
|
56 |
/* Sanity check */
|
|
57 |
HDassert(item->id > udata->nextid);
|
|
58 |
|
|
59 |
@@ -874,6 +874,40 @@ H5I_register(H5I_type_t type, const void
|
|
60 |
/* If no available ID structure, then create a new id for use, and
|
|
61 |
* allocate a new struct to house it. */
|
|
62 |
else {
|
|
63 |
+ /*
|
|
64 |
+ * This next section of code checks for the 'nextid' getting too large and
|
|
65 |
+ * wrapping around, thus necessitating checking for duplicate IDs being
|
|
66 |
+ * handed out.
|
|
67 |
+ */
|
|
68 |
+ if(type_ptr->nextid > (hid_t)ID_MASK)
|
|
69 |
+ type_ptr->wrapped = TRUE;
|
|
70 |
+
|
|
71 |
+ /*
|
|
72 |
+ * If we've wrapped around then we need to check for duplicate id's being
|
|
73 |
+ * handed out.
|
|
74 |
+ */
|
|
75 |
+ if(type_ptr->wrapped) {
|
|
76 |
+ H5I_wrap_ud_t udata; /* User data for iteration */
|
|
77 |
+ herr_t iter_status; /* Iteration status */
|
|
78 |
+
|
|
79 |
+ /* Set up user data for iteration */
|
|
80 |
+ udata.nextid = (hid_t)type_ptr->cls->reserved;
|
|
81 |
+
|
|
82 |
+ /* Iterate over all the ID nodes, looking for a gap in the ID sequence */
|
|
83 |
+ if((iter_status = H5SL_iterate(type_ptr->ids, H5I__wrapped_cb, &udata)) < 0)
|
|
84 |
+ HGOTO_ERROR(H5E_ATOM, H5E_BADITER, FAIL, "ID iteration failed")
|
|
85 |
+
|
|
86 |
+ /* If we didn't break out of the iteration and we're at the max. ID, we've used all the IDs */
|
|
87 |
+ if(0 == iter_status && udata.nextid >= ID_MASK)
|
|
88 |
+ HGOTO_ERROR(H5E_ATOM, H5E_NOIDS, FAIL, "no IDs available in type")
|
|
89 |
+
|
|
90 |
+ /* Sanity check */
|
|
91 |
+ HDassert(udata.nextid < ID_MASK);
|
|
92 |
+
|
|
93 |
+ /* Retain the next ID for the class */
|
|
94 |
+ type_ptr->nextid = udata.nextid;
|
|
95 |
+ } /* end if */
|
|
96 |
+
|
|
97 |
/* Allocate new ID struct */
|
|
98 |
if(NULL == (id_ptr = H5FL_MALLOC(H5I_id_info_t)))
|
|
99 |
HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, FAIL, "memory allocation failed")
|
|
100 |
@@ -895,40 +929,6 @@ H5I_register(H5I_type_t type, const void
|
|
101 |
HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, FAIL, "can't insert ID node into skip list")
|
|
102 |
type_ptr->id_count++;
|
|
103 |
|
|
104 |
- /*
|
|
105 |
- * This next section of code checks for the 'nextid' getting too large and
|
|
106 |
- * wrapping around, thus necessitating checking for duplicate IDs being
|
|
107 |
- * handed out.
|
|
108 |
- */
|
|
109 |
- if(type_ptr->nextid > (hid_t)ID_MASK)
|
|
110 |
- type_ptr->wrapped = TRUE;
|
|
111 |
-
|
|
112 |
- /*
|
|
113 |
- * If we've wrapped around then we need to check for duplicate id's being
|
|
114 |
- * handed out.
|
|
115 |
- */
|
|
116 |
- if(type_ptr->wrapped) {
|
|
117 |
- H5I_wrap_ud_t udata; /* User data for iteration */
|
|
118 |
- herr_t iter_status; /* Iteration status */
|
|
119 |
-
|
|
120 |
- /* Set up user data for iteration */
|
|
121 |
- udata.nextid = (hid_t)type_ptr->cls->reserved;
|
|
122 |
-
|
|
123 |
- /* Iterate over all the ID nodes, looking for a gap in the ID sequence */
|
|
124 |
- if((iter_status = H5SL_iterate(type_ptr->ids, H5I__wrapped_cb, &udata)) < 0)
|
|
125 |
- HGOTO_ERROR(H5E_ATOM, H5E_BADITER, FAIL, "ID iteration failed")
|
|
126 |
-
|
|
127 |
- /* If we didn't break out of the iteration and we're at the max. ID, we've used all the IDs */
|
|
128 |
- if(0 == iter_status && udata.nextid >= ID_MASK)
|
|
129 |
- HGOTO_ERROR(H5E_ATOM, H5E_NOIDS, FAIL, "no IDs available in type")
|
|
130 |
-
|
|
131 |
- /* Sanity check */
|
|
132 |
- HDassert(udata.nextid < ID_MASK);
|
|
133 |
-
|
|
134 |
- /* Retain the next ID for the class */
|
|
135 |
- type_ptr->nextid = udata.nextid;
|
|
136 |
- } /* end if */
|
|
137 |
-
|
|
138 |
/* Set return value */
|
|
139 |
ret_value = id_ptr->id;
|
|
140 |
|
|
141 |
@@ -1249,13 +1249,24 @@ H5I__remove_common(H5I_id_type_t *type_p
|
|
142 |
/* (Casting away const OK -QAK) */
|
|
143 |
ret_value = (void *)curr_id->obj_ptr;
|
|
144 |
|
|
145 |
- /* If there's room, and we can save IDs of this type, then
|
|
146 |
- save the struct (and its ID) for future re-use */
|
|
147 |
- if((type_ptr->cls->flags & H5I_CLASS_REUSE_IDS)
|
|
148 |
- && (type_ptr->avail_count < MAX_FREE_ID_STRUCTS)) {
|
|
149 |
- if(H5SL_insert(type_ptr->avail_ids, curr_id, &curr_id->id) < 0)
|
|
150 |
- HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, NULL, "can't insert available ID node into skip list")
|
|
151 |
- type_ptr->avail_count++;
|
|
152 |
+ /* See if we can reuse IDs of this type */
|
|
153 |
+ if(type_ptr->cls->flags & H5I_CLASS_REUSE_IDS) {
|
|
154 |
+ /* See if we can decrement the next ID for the ID class */
|
|
155 |
+ if(type_ptr->nextid == (ID_MASK & (curr_id->id + 1))) {
|
|
156 |
+ type_ptr->nextid--;
|
|
157 |
+ curr_id = H5FL_FREE(H5I_id_info_t, curr_id);
|
|
158 |
+ } /* end if */
|
|
159 |
+ else {
|
|
160 |
+ /* Store the ID on the available ID list, for later */
|
|
161 |
+ if((type_ptr->avail_count < MAX_FREE_ID_STRUCTS)
|
|
162 |
+ && (type_ptr->id_count > 1)) {
|
|
163 |
+ if(H5SL_insert(type_ptr->avail_ids, curr_id, &curr_id->id) < 0)
|
|
164 |
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, NULL, "can't insert available ID node into skip list")
|
|
165 |
+ type_ptr->avail_count++;
|
|
166 |
+ }
|
|
167 |
+ else
|
|
168 |
+ curr_id = H5FL_FREE(H5I_id_info_t, curr_id);
|
|
169 |
+ } /* end else */
|
|
170 |
} /* end if */
|
|
171 |
/* Otherwise, just toss it. */
|
|
172 |
else
|
|
173 |
Index: hdf5/src/H5Pint.c
|
|
174 |
===================================================================
|
|
175 |
--- hdf5.orig/src/H5Pint.c
|
|
176 |
+++ hdf5/src/H5Pint.c
|
|
177 |
@@ -276,7 +276,7 @@ static const H5I_class_t H5I_GENPROPCLS_
|
|
178 |
/* Generic Property List ID class */
|
|
179 |
static const H5I_class_t H5I_GENPROPLST_CLS[1] = {{
|
|
180 |
H5I_GENPROP_LST, /* ID class value */
|
|
181 |
- 0, /* Class flags */
|
|
182 |
+ H5I_CLASS_REUSE_IDS, /* Class flags */
|
|
183 |
0, /* # of reserved IDs for class */
|
|
184 |
(H5I_free_t)H5P_close /* Callback routine for closing objects of this class */
|
|
185 |
}};
|
|
186 |
Index: hdf5/test/tid.c
|
|
187 |
===================================================================
|
|
188 |
--- hdf5.orig/test/tid.c
|
|
189 |
+++ hdf5/test/tid.c
|
|
190 |
@@ -533,6 +533,103 @@ out:
|
|
191 |
return -1;
|
|
192 |
}
|
|
193 |
|
|
194 |
+/* 'Fake' free routine for ID wrapping test */
|
|
195 |
+static herr_t fake_free(void *obj)
|
|
196 |
+{
|
|
197 |
+ /* Shut compilers up */
|
|
198 |
+ obj = obj;
|
|
199 |
+
|
|
200 |
+ return(0);
|
|
201 |
+}
|
|
202 |
+
|
|
203 |
+ /* Test boundary cases with lots of IDs */
|
|
204 |
+
|
|
205 |
+/* Type IDs range from 0 to ID_MASK before wrapping around. The code will assign */
|
|
206 |
+/* IDs in sequential order until ID_MASK IDs have been given out, at which */
|
|
207 |
+/* point it will search for type IDs that were allocated but have since been */
|
|
208 |
+/* closed. */
|
|
209 |
+/* This test will allocate IDs up to ID_MASK, ensure that IDs wrap around */
|
|
210 |
+/* to low values successfully, ensure that an error is thrown when all possible */
|
|
211 |
+/* type IDs are taken, then ensure that deleting types frees up their IDs. */
|
|
212 |
+/* NOTE: this test depends on the implementation of IDs, so may break */
|
|
213 |
+/* if the implementation changes. */
|
|
214 |
+static int test_id_wrap(void)
|
|
215 |
+{
|
|
216 |
+ H5I_type_t testType; /* ID class for testing */
|
|
217 |
+ hid_t *id_array; /* Array of IDs allocated */
|
|
218 |
+ hid_t test_id; /* Test ID */
|
|
219 |
+ void *obj; /* Object pointer returned for ID */
|
|
220 |
+ unsigned u; /* Local index variable */
|
|
221 |
+ herr_t status; /* Status from routine */
|
|
222 |
+
|
|
223 |
+ /* Allocate array for storing IDs */
|
|
224 |
+ id_array = (hid_t *)HDmalloc((ID_MASK + 1) * sizeof(hid_t));
|
|
225 |
+ CHECK(id_array, NULL, "HDmalloc");
|
|
226 |
+
|
|
227 |
+ /* Register type for testing */
|
|
228 |
+ testType = H5Iregister_type((size_t)8, 0, (H5I_free_t)fake_free);
|
|
229 |
+ CHECK(testType, H5I_BADID, "H5Iregister_type");
|
|
230 |
+ if(testType == H5I_BADID)
|
|
231 |
+ goto out;
|
|
232 |
+
|
|
233 |
+ /* Get IDs, up to the maximum possible */
|
|
234 |
+ for(u = 0; u <= ID_MASK; u++) {
|
|
235 |
+ id_array[u] = H5Iregister(testType, &id_array[u]);
|
|
236 |
+ CHECK(id_array[u], FAIL, "H5Iregister");
|
|
237 |
+ if(id_array[u] < 0)
|
|
238 |
+ goto out;
|
|
239 |
+ } /* end for */
|
|
240 |
+
|
|
241 |
+ /* There should be no room at the inn for a new ID */
|
|
242 |
+ H5E_BEGIN_TRY
|
|
243 |
+ test_id = H5Iregister(testType, id_array);
|
|
244 |
+ H5E_END_TRY
|
|
245 |
+ VERIFY(test_id, H5I_BADID, "H5Iregister_type");
|
|
246 |
+ if(test_id != H5I_BADID)
|
|
247 |
+ goto out;
|
|
248 |
+
|
|
249 |
+ /* Release the first ID in the array */
|
|
250 |
+ obj = H5Iremove_verify(id_array[0], testType);
|
|
251 |
+ CHECK(obj, NULL, "H5Iremove_verify");
|
|
252 |
+ if(NULL == obj)
|
|
253 |
+ goto out;
|
|
254 |
+ VERIFY(obj, &id_array[0], "H5Iremove_verify");
|
|
255 |
+ if(&id_array[0] != obj)
|
|
256 |
+ goto out;
|
|
257 |
+
|
|
258 |
+ /* Register another object, should be room now, but will wraparound */
|
|
259 |
+ test_id = H5Iregister(testType, &id_array[0]);
|
|
260 |
+ CHECK(test_id, FAIL, "H5Iregister");
|
|
261 |
+ if(test_id < 0)
|
|
262 |
+ goto out;
|
|
263 |
+ VERIFY(test_id, id_array[0], "H5Iregister");
|
|
264 |
+ if(id_array[0] != test_id)
|
|
265 |
+ goto out;
|
|
266 |
+
|
|
267 |
+ /* Release all IDs, unregister the ID class and free the array */
|
|
268 |
+ for(u = 0; u <= ID_MASK; u++) {
|
|
269 |
+ obj = H5Iremove_verify(id_array[u], testType);
|
|
270 |
+ CHECK(obj, NULL, "H5Iremove_verify");
|
|
271 |
+ if(NULL == obj)
|
|
272 |
+ goto out;
|
|
273 |
+ VERIFY(obj, &id_array[u], "H5Iremove_verify");
|
|
274 |
+ if(&id_array[u] != obj)
|
|
275 |
+ goto out;
|
|
276 |
+ } /* end for */
|
|
277 |
+
|
|
278 |
+ status = H5Idestroy_type(testType);
|
|
279 |
+ CHECK(status, FAIL, "H5Idestroy_type");
|
|
280 |
+ if(status < 0)
|
|
281 |
+ goto out;
|
|
282 |
+
|
|
283 |
+ HDfree(id_array);
|
|
284 |
+
|
|
285 |
+ return(0);
|
|
286 |
+
|
|
287 |
+out:
|
|
288 |
+ return(-1);
|
|
289 |
+}
|
|
290 |
+
|
|
291 |
void test_ids(void)
|
|
292 |
{
|
|
293 |
if (basic_id_test() < 0) TestErrPrintf("Basic ID test failed\n");
|
|
294 |
@@ -540,5 +637,5 @@ void test_ids(void)
|
|
295 |
if (test_is_valid() < 0) TestErrPrintf("H5Iis_valid test failed\n");
|
|
296 |
if (test_get_type() < 0) TestErrPrintf("H5Iget_type test failed\n");
|
|
297 |
if (test_id_type_list() < 0) TestErrPrintf("ID type list test failed\n");
|
|
298 |
-
|
|
299 |
+ if (test_id_wrap() < 0) TestErrPrintf("ID wraparound test failed\n");
|
|
300 |
}
|