Coverage Report

Created: 2025-11-17 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Iint.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*
14
 * H5Iint.c - Private routines for handling IDs
15
 */
16
17
/****************/
18
/* Module Setup */
19
/****************/
20
21
#include "H5Imodule.h" /* This source code file is part of the H5I module */
22
23
/***********/
24
/* Headers */
25
/***********/
26
#include "H5private.h"   /* Generic Functions                        */
27
#include "H5Eprivate.h"  /* Error handling                           */
28
#include "H5FLprivate.h" /* Free Lists                               */
29
#include "H5Ipkg.h"      /* IDs                                      */
30
#include "H5MMprivate.h" /* Memory management                        */
31
#include "H5Tprivate.h"  /* Datatypes                                */
32
#include "H5VLprivate.h" /* Virtual Object Layer                     */
33
34
/****************/
35
/* Local Macros */
36
/****************/
37
38
/* Combine a Type number and an ID index into an ID */
39
4.33k
#define H5I_MAKE(g, i) ((((hid_t)(g) & TYPE_MASK) << ID_BITS) | ((hid_t)(i) & ID_MASK))
40
41
/******************/
42
/* Local Typedefs */
43
/******************/
44
45
/* User data for iterator callback for retrieving an ID corresponding to an object pointer */
46
typedef struct {
47
    const void *object;   /* object pointer to search for */
48
    H5I_type_t  obj_type; /* type of object we are searching for */
49
    hid_t       ret_id;   /* ID returned */
50
} H5I_get_id_ud_t;
51
52
/* User data for iterator callback for ID iteration */
53
typedef struct {
54
    H5I_search_func_t user_func;  /* 'User' function to invoke */
55
    void             *user_udata; /* User data to pass to 'user' function */
56
    bool              app_ref;    /* Whether this is an appl. ref. call */
57
    H5I_type_t        obj_type;   /* Type of object we are iterating over */
58
} H5I_iterate_ud_t;
59
60
/* User data for H5I__clear_type_cb */
61
typedef struct {
62
    H5I_type_info_t *type_info; /* Pointer to the type's info to be cleared */
63
    bool             force;     /* Whether to always remove the ID */
64
    bool             app_ref;   /* Whether this is an appl. ref. call */
65
} H5I_clear_type_ud_t;
66
67
/********************/
68
/* Package Typedefs */
69
/********************/
70
71
/********************/
72
/* Local Prototypes */
73
/********************/
74
75
static void  *H5I__unwrap(void *object, H5I_type_t type);
76
static herr_t H5I__mark_node(void *_id, void *key, void *udata);
77
static void  *H5I__remove_common(H5I_type_info_t *type_info, hid_t id);
78
static int    H5I__dec_ref(hid_t id, void **request);
79
static int    H5I__dec_app_ref(hid_t id, void **request);
80
static int    H5I__dec_app_ref_always_close(hid_t id, void **request);
81
static int    H5I__find_id_cb(void *_item, void *_key, void *_udata);
82
83
/*********************/
84
/* Package Variables */
85
/*********************/
86
87
/* Package initialization variable */
88
bool H5_PKG_INIT_VAR = false;
89
90
/* Declared extern in H5Ipkg.h and documented there */
91
H5I_type_info_t *H5I_type_info_array_g[H5I_MAX_NUM_TYPES];
92
int              H5I_next_type_g = (int)H5I_NTYPES;
93
94
/* Declare a free list to manage the H5I_id_info_t struct */
95
H5FL_DEFINE_STATIC(H5I_id_info_t);
96
97
/* Whether deletes are actually marks (for mark-and-sweep) */
98
static bool H5I_marking_s = false;
99
100
/*****************************/
101
/* Library Private Variables */
102
/*****************************/
103
104
/*******************/
105
/* Local Variables */
106
/*******************/
107
108
/*-------------------------------------------------------------------------
109
 * Function:    H5I_term_package
110
 *
111
 * Purpose:     Terminate the H5I interface: release all memory, reset all
112
 *              global variables to initial values. This only happens if all
113
 *              types have been destroyed from other interfaces.
114
 *
115
 * Return:      Success:    Positive if any action was taken that might
116
 *                          affect some other interface; zero otherwise.
117
 *
118
 *              Failure:    Negative
119
 *
120
 *-------------------------------------------------------------------------
121
 */
122
int
123
H5I_term_package(void)
124
186
{
125
186
    int in_use = 0; /* Number of ID types still in use */
126
127
186
    FUNC_ENTER_NOAPI_NOINIT_NOERR
128
129
2
    if (H5_PKG_INIT_VAR) {
130
2
        H5I_type_info_t *type_info = NULL; /* Pointer to ID type */
131
2
        int              i;
132
133
        /* Count the number of types still in use */
134
36
        for (i = 0; i < H5I_next_type_g; i++)
135
34
            if ((type_info = H5I_type_info_array_g[i]) && type_info->hash_table)
136
0
                in_use++;
137
138
        /* If no types are still being used then clean up */
139
2
        if (0 == in_use) {
140
36
            for (i = 0; i < H5I_next_type_g; i++) {
141
34
                type_info = H5I_type_info_array_g[i];
142
34
                if (type_info) {
143
0
                    assert(NULL == type_info->hash_table);
144
0
                    type_info                = H5MM_xfree(type_info);
145
0
                    H5I_type_info_array_g[i] = NULL;
146
0
                    in_use++;
147
0
                }
148
34
            }
149
150
            /* Mark interface closed */
151
2
            if (0 == in_use)
152
2
                H5_PKG_INIT_VAR = false;
153
2
        }
154
2
    }
155
156
2
    FUNC_LEAVE_NOAPI(in_use)
157
186
} /* end H5I_term_package() */
158
159
/*-------------------------------------------------------------------------
160
 * Function:    H5I__register_type_common
161
 *
162
 * Purpose:     Common functionality for H5Iregister_type(1|2)
163
 *
164
 * Return:      Success:    Type ID of the new type
165
 *              Failure:    H5I_BADID
166
 *-------------------------------------------------------------------------
167
 */
168
H5I_type_t
169
H5I__register_type_common(unsigned reserved, H5I_free_t free_func)
170
0
{
171
0
    H5I_class_t *cls       = NULL;      /* New ID class */
172
0
    H5I_type_t   new_type  = H5I_BADID; /* New ID type value */
173
0
    H5I_type_t   ret_value = H5I_BADID; /* Return value */
174
175
0
    FUNC_ENTER_PACKAGE
176
177
    /* Generate a new H5I_type_t value */
178
179
    /* Increment the number of types */
180
0
    if (H5I_next_type_g < H5I_MAX_NUM_TYPES) {
181
0
        new_type = (H5I_type_t)H5I_next_type_g;
182
0
        H5I_next_type_g++;
183
0
    }
184
0
    else {
185
0
        bool done; /* Indicate that search was successful */
186
0
        int  i;
187
188
        /* Look for a free type to give out */
189
0
        done = false;
190
0
        for (i = H5I_NTYPES; i < H5I_MAX_NUM_TYPES && done == false; i++) {
191
0
            if (NULL == H5I_type_info_array_g[i]) {
192
                /* Found a free type ID */
193
0
                new_type = (H5I_type_t)i;
194
0
                done     = true;
195
0
            }
196
0
        }
197
198
        /* Verify that we found a type to give out */
199
0
        if (done == false)
200
0
            HGOTO_ERROR(H5E_ID, H5E_NOSPACE, H5I_BADID, "Maximum number of ID types exceeded");
201
0
    }
202
203
    /* Allocate new ID class */
204
0
    if (NULL == (cls = H5MM_calloc(sizeof(H5I_class_t))))
205
0
        HGOTO_ERROR(H5E_ID, H5E_CANTALLOC, H5I_BADID, "ID class allocation failed");
206
207
    /* Initialize class fields */
208
0
    cls->type      = new_type;
209
0
    cls->flags     = H5I_CLASS_IS_APPLICATION;
210
0
    cls->reserved  = reserved;
211
0
    cls->free_func = free_func;
212
213
    /* Register the new ID class */
214
0
    if (H5I_register_type(cls) < 0)
215
0
        HGOTO_ERROR(H5E_ID, H5E_CANTINIT, H5I_BADID, "can't initialize ID class");
216
217
    /* Set return value */
218
0
    ret_value = new_type;
219
220
0
done:
221
    /* Clean up on error */
222
0
    if (ret_value == H5I_BADID)
223
0
        if (cls)
224
0
            cls = H5MM_xfree(cls);
225
226
0
    FUNC_LEAVE_NOAPI(ret_value)
227
0
} /* end H5I__register_type_common() */
228
229
/*-------------------------------------------------------------------------
230
 * Function:    H5I_register_type
231
 *
232
 * Purpose:     Creates a new type of ID's to give out.
233
 *              The class is initialized or its reference count is incremented
234
 *              (if it is already initialized).
235
 *
236
 * Return:      SUCCEED/FAIL
237
 *
238
 *-------------------------------------------------------------------------
239
 */
240
herr_t
241
H5I_register_type(const H5I_class_t *cls)
242
30
{
243
30
    H5I_type_info_t *type_info = NULL;    /* Pointer to the ID type*/
244
30
    herr_t           ret_value = SUCCEED; /* Return value */
245
246
30
    FUNC_ENTER_NOAPI(FAIL)
247
248
    /* Sanity check */
249
30
    assert(cls);
250
30
    assert(cls->type > 0 && (int)cls->type < H5I_MAX_NUM_TYPES);
251
252
    /* Initialize the type */
253
30
    if (NULL == H5I_type_info_array_g[cls->type]) {
254
        /* Allocate the type information for new type */
255
30
        if (NULL == (type_info = (H5I_type_info_t *)H5MM_calloc(sizeof(H5I_type_info_t))))
256
0
            HGOTO_ERROR(H5E_ID, H5E_CANTALLOC, FAIL, "ID type allocation failed");
257
30
        H5I_type_info_array_g[cls->type] = type_info;
258
30
    }
259
0
    else {
260
        /* Get the pointer to the existing type */
261
0
        type_info = H5I_type_info_array_g[cls->type];
262
0
    }
263
264
    /* Initialize the ID type structure for new types */
265
30
    if (type_info->init_count == 0) {
266
30
        type_info->cls          = cls;
267
30
        type_info->id_count     = 0;
268
30
        type_info->nextid       = cls->reserved;
269
30
        type_info->last_id_info = NULL;
270
30
        type_info->hash_table   = NULL;
271
30
    }
272
273
    /* Increment the count of the times this type has been initialized */
274
30
    type_info->init_count++;
275
276
30
done:
277
    /* Clean up on error */
278
30
    if (ret_value < 0)
279
0
        if (type_info)
280
0
            H5MM_free(type_info);
281
282
30
    FUNC_LEAVE_NOAPI(ret_value)
283
30
} /* end H5I_register_type() */
284
285
/*-------------------------------------------------------------------------
286
 * Function:    H5I_nmembers
287
 *
288
 * Purpose:     Returns the number of members in a type.
289
 *
290
 * Return:      Success:    Number of members; zero if the type is empty
291
 *                          or has been deleted.
292
 *
293
 *              Failure:    Negative
294
 *
295
 *-------------------------------------------------------------------------
296
 */
297
int64_t
298
H5I_nmembers(H5I_type_t type)
299
60
{
300
60
    H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
301
60
    int64_t          ret_value = 0;    /* Return value */
302
303
60
    FUNC_ENTER_NOAPI((-1))
304
305
    /* Validate parameter */
306
60
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
307
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
308
60
    if (NULL == (type_info = H5I_type_info_array_g[type]) || type_info->init_count <= 0)
309
0
        HGOTO_DONE(0);
310
311
    /* Set return value */
312
60
    H5_CHECKED_ASSIGN(ret_value, int64_t, type_info->id_count, uint64_t);
313
314
60
done:
315
60
    FUNC_LEAVE_NOAPI(ret_value)
316
60
} /* end H5I_nmembers() */
317
318
/*-------------------------------------------------------------------------
319
 * Function:    H5I__unwrap
320
 *
321
 * Purpose:     Unwraps the object pointer for the 'item' that corresponds
322
 *              to an ID.
323
 *
324
 * Return:      Pointer to the unwrapped pointer (can't fail)
325
 *
326
 *-------------------------------------------------------------------------
327
 */
328
static void *
329
H5I__unwrap(void *object, H5I_type_t type)
330
568
{
331
568
    void *ret_value = NULL; /* Return value */
332
333
568
    FUNC_ENTER_PACKAGE_NOERR
334
335
    /* Sanity checks */
336
568
    assert(object);
337
338
    /* The stored object pointer might be an H5VL_object_t, in which
339
     * case we'll need to get the wrapped object struct (H5F_t *, etc.).
340
     */
341
568
    if (H5I_FILE == type || H5I_GROUP == type || H5I_DATASET == type || H5I_ATTR == type) {
342
0
        const H5VL_object_t *vol_obj;
343
344
0
        vol_obj   = (const H5VL_object_t *)object;
345
0
        ret_value = H5VL_object_data(vol_obj);
346
0
    }
347
568
    else if (H5I_DATATYPE == type) {
348
206
        H5T_t *dt = (H5T_t *)object;
349
350
206
        ret_value = (void *)H5T_get_actual_type(dt);
351
206
    }
352
362
    else
353
362
        ret_value = object;
354
355
568
    FUNC_LEAVE_NOAPI(ret_value)
356
568
} /* end H5I__unwrap() */
357
358
/*-------------------------------------------------------------------------
359
 * Function:    H5I_clear_type
360
 *
361
 * Purpose:     Removes all objects from the type, calling the free
362
 *              function for each object regardless of the reference count.
363
 *
364
 * Return:      SUCCEED/FAIL
365
 *
366
 *-------------------------------------------------------------------------
367
 */
368
herr_t
369
H5I_clear_type(H5I_type_t type, bool force, bool app_ref)
370
46
{
371
46
    H5I_clear_type_ud_t udata; /* udata struct for callback */
372
46
    H5I_id_info_t      *item      = NULL;
373
46
    H5I_id_info_t      *tmp       = NULL;
374
46
    herr_t              ret_value = SUCCEED; /* Return value */
375
376
46
    FUNC_ENTER_NOAPI(FAIL)
377
378
    /* Validate parameters */
379
46
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
380
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
381
382
46
    udata.type_info = H5I_type_info_array_g[type];
383
46
    if (udata.type_info == NULL || udata.type_info->init_count <= 0)
384
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type");
385
386
    /* Finish constructing udata */
387
46
    udata.force   = force;
388
46
    udata.app_ref = app_ref;
389
390
    /* Clearing a type is done in two phases (mark-and-sweep). This is because
391
     * the type's free callback can free other IDs, potentially corrupting
392
     * the data structure during the traversal.
393
     */
394
395
    /* Set marking flag */
396
46
    H5I_marking_s = true;
397
398
    /* Mark nodes for deletion */
399
46
    HASH_ITER(hh, udata.type_info->hash_table, item, tmp)
400
2.07k
    {
401
2.07k
        if (!item->marked)
402
1.71k
            if (H5I__mark_node((void *)item, NULL, (void *)&udata) < 0)
403
0
                HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed while clearing the ID type");
404
2.07k
    }
405
406
    /* Unset marking flag */
407
46
    H5I_marking_s = false;
408
409
    /* Perform sweep */
410
46
    HASH_ITER(hh, udata.type_info->hash_table, item, tmp)
411
2.07k
    {
412
2.07k
        if (item->marked) {
413
2.07k
            HASH_DELETE(hh, udata.type_info->hash_table, item);
414
2.07k
            item = H5FL_FREE(H5I_id_info_t, item);
415
2.07k
        }
416
2.07k
    }
417
418
46
done:
419
46
    FUNC_LEAVE_NOAPI(ret_value)
420
46
} /* end H5I_clear_type() */
421
422
/*-------------------------------------------------------------------------
423
 * Function:    H5I__mark_node
424
 *
425
 * Purpose:     Attempts to mark the node for freeing and calls the free
426
 *              function for the object, if any
427
 *
428
 * Return:      SUCCEED/FAIL
429
 *
430
 *-------------------------------------------------------------------------
431
 */
432
static herr_t
433
H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata)
434
1.71k
{
435
1.71k
    H5I_id_info_t       *info  = (H5I_id_info_t *)_info;        /* Current ID info being worked with */
436
1.71k
    H5I_clear_type_ud_t *udata = (H5I_clear_type_ud_t *)_udata; /* udata struct */
437
1.71k
    bool                 mark  = false;
438
439
1.71k
    FUNC_ENTER_PACKAGE_NOERR
440
441
    /* Sanity checks */
442
1.71k
    assert(info);
443
1.71k
    assert(udata);
444
1.71k
    assert(udata->type_info);
445
446
    /* Do nothing to the object if the reference count is larger than
447
     * one and forcing is off.
448
     */
449
1.71k
    if (udata->force || (info->count - (!udata->app_ref * info->app_count)) <= 1) {
450
        /* Check if this is an un-realized future object */
451
1.71k
        if (info->is_future) {
452
0
            herr_t status;
453
454
            /* Prepare & restore library for user callback */
455
0
            H5_BEFORE_USER_CB_NOCHECK
456
0
                {
457
                    /* Discard the future object */
458
0
                    status = (info->discard_cb)(info->u.object);
459
0
                }
460
0
            H5_AFTER_USER_CB_NOCHECK
461
0
            if (status < 0) {
462
0
                if (udata->force) {
463
                    /* Indicate node should be removed from list */
464
0
                    mark = true;
465
0
                }
466
0
            }
467
0
            else {
468
                /* Indicate node should be removed from list */
469
0
                mark = true;
470
0
            }
471
0
        }
472
1.71k
        else {
473
            /* Check for a 'free' function and call it, if it exists */
474
1.71k
            if (udata->type_info->cls->free_func) {
475
1.71k
                herr_t status;
476
477
                /* Prepare & restore library for user callback */
478
1.71k
                H5_BEFORE_USER_CB_NOCHECK
479
1.71k
                    {
480
1.71k
                        status = (udata->type_info->cls->free_func)(info->u.object, H5_REQUEST_NULL);
481
1.71k
                    }
482
1.71k
                H5_AFTER_USER_CB_NOCHECK
483
1.71k
                if (status < 0) {
484
0
                    if (udata->force) {
485
                        /* Indicate node should be removed from list */
486
0
                        mark = true;
487
0
                    }
488
0
                }
489
1.71k
                else
490
                    /* Indicate node should be removed from list */
491
1.71k
                    mark = true;
492
1.71k
            }
493
0
            else {
494
                /* Indicate node should be removed from list */
495
0
                mark = true;
496
0
            }
497
1.71k
        }
498
499
        /* Remove ID if requested */
500
1.71k
        if (mark) {
501
            /* Mark ID for deletion */
502
1.71k
            info->marked = true;
503
504
            /* Decrement the number of IDs in the type */
505
1.71k
            udata->type_info->id_count--;
506
1.71k
        }
507
1.71k
    }
508
509
1.71k
    FUNC_LEAVE_NOAPI(SUCCEED)
510
1.71k
} /* end H5I__mark_node() */
511
512
/*-------------------------------------------------------------------------
513
 * Function:    H5I__destroy_type
514
 *
515
 * Purpose:     Destroys a type along with all IDs in that type
516
 *              regardless of their reference counts. Destroying IDs
517
 *              involves calling the free-func for each ID's object and
518
 *              then adding the ID struct to the ID free list.
519
 *
520
 * Return:      SUCCEED/FAIL
521
 *
522
 *-------------------------------------------------------------------------
523
 */
524
herr_t
525
H5I__destroy_type(H5I_type_t type)
526
30
{
527
30
    H5I_type_info_t *type_info = NULL;    /* Pointer to the ID type */
528
30
    herr_t           ret_value = SUCCEED; /* Return value */
529
530
30
    FUNC_ENTER_PACKAGE
531
532
    /* Validate parameter */
533
30
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
534
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
535
536
30
    type_info = H5I_type_info_array_g[type];
537
30
    if (type_info == NULL || type_info->init_count <= 0)
538
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type");
539
540
    /* Close/clear/destroy all IDs for this type */
541
30
    if (H5I_clear_type(type, true, false) < 0)
542
0
        HGOTO_ERROR(H5E_ID, H5E_CANTRELEASE, FAIL, "unable to release IDs for type");
543
544
    /* Check if we should release the ID class */
545
30
    if (type_info->cls->flags & H5I_CLASS_IS_APPLICATION)
546
0
        type_info->cls = H5MM_xfree_const(type_info->cls);
547
548
30
    HASH_CLEAR(hh, type_info->hash_table);
549
30
    type_info->hash_table = NULL;
550
551
30
    type_info = H5MM_xfree(type_info);
552
553
30
    H5I_type_info_array_g[type] = NULL;
554
555
30
done:
556
30
    FUNC_LEAVE_NOAPI(ret_value)
557
30
} /* end H5I__destroy_type() */
558
559
/*-------------------------------------------------------------------------
560
 * Function:    H5I__register
561
 *
562
 * Purpose:     Registers an OBJECT in a TYPE and returns an ID for it.
563
 *              This routine does _not_ check for unique-ness of the objects,
564
 *              if you register an object twice, you will get two different
565
 *              IDs for it.  This routine does make certain that each ID in a
566
 *              type is unique.  IDs are created by getting a unique number
567
 *              for the type the ID is in and incorporating the TYPE into
568
 *              the ID which is returned to the user.
569
 *
570
 *              IDs are marked as "future" if the realize_cb and discard_cb
571
 *              parameters are non-NULL.
572
 *
573
 * Return:      Success:    New object ID
574
 *              Failure:    H5I_INVALID_HID
575
 *
576
 *-------------------------------------------------------------------------
577
 */
578
hid_t
579
H5I__register(H5I_type_t type, const void *object, bool app_ref, H5I_future_realize_func_t realize_cb,
580
              H5I_future_discard_func_t discard_cb)
581
4.33k
{
582
4.33k
    H5I_type_info_t *type_info = NULL;            /* Pointer to the type */
583
4.33k
    H5I_id_info_t   *info      = NULL;            /* Pointer to the new ID information */
584
4.33k
    hid_t            new_id    = H5I_INVALID_HID; /* New ID */
585
4.33k
    hid_t            ret_value = H5I_INVALID_HID; /* Return value */
586
587
4.33k
    FUNC_ENTER_PACKAGE
588
589
    /* Check arguments */
590
4.33k
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
591
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, H5I_INVALID_HID, "invalid type number");
592
4.33k
    type_info = H5I_type_info_array_g[type];
593
4.33k
    if ((NULL == type_info) || (type_info->init_count <= 0))
594
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, H5I_INVALID_HID, "invalid type");
595
4.33k
    if (NULL == (info = H5FL_CALLOC(H5I_id_info_t)))
596
0
        HGOTO_ERROR(H5E_ID, H5E_NOSPACE, H5I_INVALID_HID, "memory allocation failed");
597
598
    /* Create the struct & its ID */
599
4.33k
    new_id           = H5I_MAKE(type, type_info->nextid);
600
4.33k
    info->id         = new_id;
601
4.33k
    info->count      = 1; /* initial reference count */
602
4.33k
    info->app_count  = !!app_ref;
603
4.33k
    info->u.c_object = object;
604
4.33k
    info->is_future  = (NULL != realize_cb);
605
4.33k
    info->realize_cb = realize_cb;
606
4.33k
    info->discard_cb = discard_cb;
607
4.33k
    info->marked     = false;
608
609
    /* Insert into the type */
610
4.33k
    HASH_ADD(hh, type_info->hash_table, id, sizeof(hid_t), info);
611
4.33k
    type_info->id_count++;
612
4.33k
    type_info->nextid++;
613
614
    /* Sanity check for the 'nextid' getting too large and wrapping around */
615
4.33k
    assert(type_info->nextid <= ID_MASK);
616
617
    /* Set the most recent ID to this object */
618
4.33k
    type_info->last_id_info = info;
619
620
    /* Set return value */
621
4.33k
    ret_value = new_id;
622
623
4.33k
done:
624
4.33k
    FUNC_LEAVE_NOAPI(ret_value)
625
4.33k
} /* end H5I__register() */
626
627
/*-------------------------------------------------------------------------
628
 * Function:    H5I_register
629
 *
630
 * Purpose:     Library-private wrapper for H5I__register.
631
 *
632
 * Return:      Success:    New object ID
633
 *              Failure:    H5I_INVALID_HID
634
 *
635
 *-------------------------------------------------------------------------
636
 */
637
hid_t
638
H5I_register(H5I_type_t type, const void *object, bool app_ref)
639
4.33k
{
640
4.33k
    hid_t ret_value = H5I_INVALID_HID; /* Return value */
641
642
4.33k
    FUNC_ENTER_NOAPI(H5I_INVALID_HID)
643
644
    /* Sanity checks */
645
4.33k
    assert(type >= H5I_FILE && type < H5I_NTYPES);
646
4.33k
    assert(object);
647
648
    /* Retrieve ID for object */
649
4.33k
    if (H5I_INVALID_HID == (ret_value = H5I__register(type, object, app_ref, NULL, NULL)))
650
0
        HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register object");
651
652
4.33k
done:
653
4.33k
    FUNC_LEAVE_NOAPI(ret_value)
654
4.33k
} /* end H5I_register() */
655
656
/*-------------------------------------------------------------------------
657
 * Function:    H5I_register_using_existing_id
658
 *
659
 * Purpose:     Registers an OBJECT in a TYPE with the supplied ID for it.
660
 *              This routine will check to ensure the supplied ID is not already
661
 *              in use, and ensure that it is a valid ID for the given type,
662
 *              but will NOT check to ensure the OBJECT is not already
663
 *              registered (thus, it is possible to register one object under
664
 *              multiple IDs).
665
 *
666
 * NOTE:        Intended for use in refresh calls, where we have to close
667
 *              and re-open the underlying data, then hook the object back
668
 *              up to the original ID.
669
 *
670
 * Return:      SUCCEED/FAIL
671
 *
672
 *-------------------------------------------------------------------------
673
 */
674
herr_t
675
H5I_register_using_existing_id(H5I_type_t type, void *object, bool app_ref, hid_t existing_id)
676
0
{
677
0
    H5I_type_info_t *type_info = NULL;    /* Pointer to the type */
678
0
    H5I_id_info_t   *info      = NULL;    /* Pointer to the new ID information */
679
0
    herr_t           ret_value = SUCCEED; /* Return value */
680
681
0
    FUNC_ENTER_NOAPI(FAIL)
682
683
    /* Check arguments */
684
0
    assert(object);
685
686
    /* Make sure ID is not already in use */
687
0
    if (NULL != (info = H5I__find_id(existing_id)))
688
0
        HGOTO_ERROR(H5E_ID, H5E_BADRANGE, FAIL, "ID already in use");
689
690
    /* Make sure type number is valid */
691
0
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
692
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
693
694
    /* Get type pointer from list of types */
695
0
    type_info = H5I_type_info_array_g[type];
696
697
0
    if (NULL == type_info || type_info->init_count <= 0)
698
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type");
699
700
    /* Make sure requested ID belongs to object's type */
701
0
    if (H5I_TYPE(existing_id) != type)
702
0
        HGOTO_ERROR(H5E_ID, H5E_BADRANGE, FAIL, "invalid type for provided ID");
703
704
    /* Allocate new structure to house this ID */
705
0
    if (NULL == (info = H5FL_CALLOC(H5I_id_info_t)))
706
0
        HGOTO_ERROR(H5E_ID, H5E_NOSPACE, FAIL, "memory allocation failed");
707
708
    /* Create the struct & insert requested ID */
709
0
    info->id        = existing_id;
710
0
    info->count     = 1; /* initial reference count*/
711
0
    info->app_count = !!app_ref;
712
0
    info->u.object  = object;
713
    /* This API call is only used by the native VOL connector, which is
714
     * not asynchronous.
715
     */
716
0
    info->is_future  = false;
717
0
    info->realize_cb = NULL;
718
0
    info->discard_cb = NULL;
719
0
    info->marked     = false;
720
721
    /* Insert into the type */
722
0
    HASH_ADD(hh, type_info->hash_table, id, sizeof(hid_t), info);
723
0
    type_info->id_count++;
724
725
    /* Set the most recent ID to this object */
726
0
    type_info->last_id_info = info;
727
728
0
done:
729
0
    FUNC_LEAVE_NOAPI(ret_value)
730
0
} /* end H5I_register_using_existing_id() */
731
732
/*-------------------------------------------------------------------------
733
 * Function:    H5I_subst
734
 *
735
 * Purpose:     Substitute a new object pointer for the specified ID.
736
 *
737
 * Return:      Success:    Non-NULL previous object pointer associated
738
 *                          with the specified ID.
739
 *              Failure:    NULL
740
 *
741
 *-------------------------------------------------------------------------
742
 */
743
void *
744
H5I_subst(hid_t id, const void *new_object)
745
0
{
746
0
    H5I_id_info_t *info      = NULL; /* Pointer to the ID's info */
747
0
    void          *ret_value = NULL; /* Return value */
748
749
0
    FUNC_ENTER_NOAPI(NULL)
750
751
    /* General lookup of the ID */
752
0
    if (NULL == (info = H5I__find_id(id)))
753
0
        HGOTO_ERROR(H5E_ID, H5E_NOTFOUND, NULL, "can't get ID ref count");
754
755
    /* Get the old object pointer to return */
756
0
    ret_value = info->u.object;
757
758
    /* Set the new object pointer for the ID */
759
0
    info->u.c_object = new_object;
760
761
0
done:
762
0
    FUNC_LEAVE_NOAPI(ret_value)
763
0
} /* end H5I_subst() */
764
765
/*-------------------------------------------------------------------------
766
 * Function:    H5I_object
767
 *
768
 * Purpose:     Find an object pointer for the specified ID.
769
 *
770
 * Return:      Success:    Non-NULL object pointer associated with the
771
 *                          specified ID
772
 *
773
 *              Failure:    NULL
774
 *
775
 *-------------------------------------------------------------------------
776
 */
777
void *
778
H5I_object(hid_t id)
779
15.4k
{
780
15.4k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID info */
781
15.4k
    void          *ret_value = NULL; /* Return value */
782
783
15.4k
    FUNC_ENTER_NOAPI_NOERR
784
785
    /* General lookup of the ID */
786
15.4k
    if (NULL != (info = H5I__find_id(id)))
787
        /* Get the object pointer to return */
788
15.4k
        ret_value = info->u.object;
789
790
15.4k
    FUNC_LEAVE_NOAPI(ret_value)
791
15.4k
} /* end H5I_object() */
792
793
/*-------------------------------------------------------------------------
794
 * Function:    H5I_object_verify
795
 *
796
 * Purpose:     Find an object pointer for the specified ID, verifying that
797
 *              its in a particular type.
798
 *
799
 * Return:      Success:    Non-NULL object pointer associated with the
800
 *                          specified ID.
801
 *              Failure:    NULL
802
 *
803
 *-------------------------------------------------------------------------
804
 */
805
void *
806
H5I_object_verify(hid_t id, H5I_type_t type)
807
110k
{
808
110k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID info */
809
110k
    void          *ret_value = NULL; /* Return value */
810
811
110k
    FUNC_ENTER_NOAPI_NOERR
812
813
110k
    assert(type >= 1 && (int)type < H5I_next_type_g);
814
815
    /* Verify that the type of the ID is correct & lookup the ID */
816
110k
    if (type == H5I_TYPE(id) && NULL != (info = H5I__find_id(id)))
817
        /* Get the object pointer to return */
818
110k
        ret_value = info->u.object;
819
820
110k
    FUNC_LEAVE_NOAPI(ret_value)
821
110k
} /* H5I_object_verify() */
822
823
/*-------------------------------------------------------------------------
824
 * Function:    H5I_get_type
825
 *
826
 * Purpose:     Given an object ID return the type to which it
827
 *              belongs.  The ID need not be the ID of an object which
828
 *              currently exists because the type number is encoded
829
 *              in the object ID.
830
 *
831
 * Return:      Success:    A positive integer (corresponding to an H5I_type_t
832
 *                          enum value for library ID types, but not for user
833
 *                          ID types).
834
 *              Failure:    H5I_BADID
835
 *
836
 *-------------------------------------------------------------------------
837
 */
838
H5I_type_t
839
H5I_get_type(hid_t id)
840
8.41k
{
841
8.41k
    H5I_type_t ret_value = H5I_BADID; /* Return value */
842
843
8.41k
    FUNC_ENTER_NOAPI_NOERR
844
845
8.41k
    if (id > 0)
846
8.39k
        ret_value = H5I_TYPE(id);
847
848
8.41k
    assert(ret_value >= H5I_BADID && (int)ret_value < H5I_next_type_g);
849
850
8.41k
    FUNC_LEAVE_NOAPI(ret_value)
851
8.41k
} /* end H5I_get_type() */
852
853
/*-------------------------------------------------------------------------
854
 * Function:    H5I_is_file_object
855
 *
856
 * Purpose:     Convenience function to determine if an ID represents
857
 *              a file object.
858
 *
859
 *              In H5O calls, you can't use object_verify to ensure
860
 *              the ID was of the correct class since there's no
861
 *              H5I_OBJECT ID class.
862
 *
863
 * Return:      Success:    true/false
864
 *              Failure:    FAIL
865
 *
866
 *-------------------------------------------------------------------------
867
 */
868
htri_t
869
H5I_is_file_object(hid_t id)
870
0
{
871
0
    H5I_type_t type      = H5I_get_type(id);
872
0
    htri_t     ret_value = FAIL;
873
874
0
    FUNC_ENTER_NOAPI(FAIL)
875
876
    /* Fail if the ID type is out of range */
877
0
    if (type < 1 || type >= H5I_NTYPES)
878
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "ID type out of range");
879
880
    /* Return true if the ID is a file object (dataset, group, map, or committed
881
     * datatype), false otherwise.
882
     */
883
0
    if (H5I_DATASET == type || H5I_GROUP == type || H5I_MAP == type)
884
0
        ret_value = true;
885
0
    else if (H5I_DATATYPE == type) {
886
887
0
        H5T_t *dt = NULL;
888
889
0
        if (NULL == (dt = (H5T_t *)H5I_object(id)))
890
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unable to get underlying datatype struct");
891
892
0
        ret_value = H5T_is_named(dt);
893
0
    }
894
0
    else
895
0
        ret_value = false;
896
897
0
done:
898
0
    FUNC_LEAVE_NOAPI(ret_value)
899
0
} /* H5I_is_file_object() */
900
901
/*-------------------------------------------------------------------------
902
 * Function:    H5I__remove_verify
903
 *
904
 * Purpose:     Removes the specified ID from its type, first checking that
905
 *              the ID's type is the same as the ID type supplied as an argument
906
 *
907
 * Return:      Success:    A pointer to the object that was removed, the
908
 *                          same pointer which would have been found by
909
 *                          calling H5I_object().
910
 *              Failure:    NULL
911
 *
912
 *-------------------------------------------------------------------------
913
 */
914
void *
915
H5I__remove_verify(hid_t id, H5I_type_t type)
916
0
{
917
0
    void *ret_value = NULL; /*return value            */
918
919
0
    FUNC_ENTER_PACKAGE_NOERR
920
921
    /* Argument checking will be performed by H5I_remove() */
922
923
    /* Verify that the type of the ID is correct */
924
0
    if (type == H5I_TYPE(id))
925
0
        ret_value = H5I_remove(id);
926
927
0
    FUNC_LEAVE_NOAPI(ret_value)
928
0
} /* end H5I__remove_verify() */
929
930
/*-------------------------------------------------------------------------
931
 * Function:    H5I__remove_common
932
 *
933
 * Purpose:     Common code to remove a specified ID from its type.
934
 *
935
 * Return:      Success:    A pointer to the object that was removed, the
936
 *                          same pointer which would have been found by
937
 *                          calling H5I_object().
938
 *              Failure:    NULL
939
 *
940
 *-------------------------------------------------------------------------
941
 */
942
static void *
943
H5I__remove_common(H5I_type_info_t *type_info, hid_t id)
944
2.61k
{
945
2.61k
    H5I_id_info_t *info      = NULL; /* Pointer to the current ID */
946
2.61k
    void          *ret_value = NULL; /* Return value */
947
948
2.61k
    FUNC_ENTER_PACKAGE
949
950
    /* Sanity check */
951
2.61k
    assert(type_info);
952
953
    /* Delete or mark the node */
954
2.61k
    HASH_FIND(hh, type_info->hash_table, &id, sizeof(hid_t), info);
955
2.61k
    if (info) {
956
2.61k
        assert(!info->marked);
957
2.61k
        if (!H5I_marking_s)
958
2.61k
            HASH_DELETE(hh, type_info->hash_table, info);
959
362
        else
960
362
            info->marked = true;
961
2.61k
    }
962
0
    else
963
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, NULL, "can't remove ID node from hash table");
964
965
    /* Check if this ID was the last one accessed */
966
2.61k
    if (type_info->last_id_info == info)
967
2.25k
        type_info->last_id_info = NULL;
968
969
2.61k
    ret_value = info->u.object;
970
971
2.61k
    if (!H5I_marking_s)
972
2.25k
        info = H5FL_FREE(H5I_id_info_t, info);
973
974
    /* Decrement the number of IDs in the type */
975
2.61k
    (type_info->id_count)--;
976
977
2.61k
done:
978
2.61k
    FUNC_LEAVE_NOAPI(ret_value)
979
2.61k
} /* end H5I__remove_common() */
980
981
/*-------------------------------------------------------------------------
982
 * Function:    H5I_remove
983
 *
984
 * Purpose:     Removes the specified ID from its type.
985
 *
986
 * Return:      Success:    A pointer to the object that was removed, the
987
 *                          same pointer which would have been found by
988
 *                          calling H5I_object().
989
 *              Failure:    NULL
990
 *
991
 *-------------------------------------------------------------------------
992
 */
993
void *
994
H5I_remove(hid_t id)
995
362
{
996
362
    H5I_type_info_t *type_info = NULL;      /* Pointer to the ID type */
997
362
    H5I_type_t       type      = H5I_BADID; /* ID's type */
998
362
    void            *ret_value = NULL;      /* Return value */
999
1000
362
    FUNC_ENTER_NOAPI(NULL)
1001
1002
    /* Check arguments */
1003
362
    type = H5I_TYPE(id);
1004
362
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1005
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number");
1006
362
    type_info = H5I_type_info_array_g[type];
1007
362
    if (type_info == NULL || type_info->init_count <= 0)
1008
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, NULL, "invalid type");
1009
1010
    /* Remove the node from the type */
1011
362
    if (NULL == (ret_value = H5I__remove_common(type_info, id)))
1012
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, NULL, "can't remove ID node");
1013
1014
362
done:
1015
362
    FUNC_LEAVE_NOAPI(ret_value)
1016
362
} /* end H5I_remove() */
1017
1018
/*-------------------------------------------------------------------------
1019
 * Function:    H5I__dec_ref
1020
 *
1021
 * Purpose:     This will fail if the type is not a reference counted type.
1022
 *              The ID type's 'free' function will be called for the ID
1023
 *              if the reference count for the ID reaches 0 and a free
1024
 *              function has been defined at type creation time.
1025
 *
1026
 * Note:        Allows for asynchronous 'close' operation on object, with
1027
 *              request != H5_REQUEST_NULL.
1028
 *
1029
 * Return:      Success:    New reference count
1030
 *              Failure:    -1
1031
 *
1032
 *-------------------------------------------------------------------------
1033
 */
1034
static int
1035
H5I__dec_ref(hid_t id, void **request)
1036
4.28k
{
1037
4.28k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID */
1038
4.28k
    int            ret_value = 0;    /* Return value */
1039
1040
4.28k
    FUNC_ENTER_PACKAGE
1041
1042
    /* Sanity check */
1043
4.28k
    assert(id >= 0);
1044
1045
    /* General lookup of the ID */
1046
4.28k
    if (NULL == (info = H5I__find_id(id)))
1047
0
        HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID");
1048
1049
    /* If this is the last reference to the object then invoke the type's
1050
     * free method on the object. If the free method is undefined or
1051
     * successful then remove the object from the type; otherwise leave
1052
     * the object in the type without decrementing the reference
1053
     * count. If the reference count is more than one then decrement the
1054
     * reference count without calling the free method.
1055
     *
1056
     * Beware: the free method may call other H5I functions.
1057
     *
1058
     * If an object is closing, we can remove the ID even though the free
1059
     * method might fail.  This can happen when a mandatory filter fails to
1060
     * write when a dataset is closed and the chunk cache is flushed to the
1061
     * file.  We have to close the dataset anyway. (SLU - 2010/9/7)
1062
     */
1063
4.28k
    if (1 == info->count) {
1064
2.84k
        H5I_type_info_t *type_info; /*ptr to the type    */
1065
2.84k
        bool             remove_node = false;
1066
1067
        /* Get the ID's type */
1068
2.84k
        type_info = H5I_type_info_array_g[H5I_TYPE(id)];
1069
1070
2.84k
        if (type_info->cls->free_func) {
1071
2.84k
            herr_t status;
1072
1073
            /* Prepare & restore library for user callback */
1074
2.84k
            H5_BEFORE_USER_CB((-1))
1075
2.84k
                {
1076
2.84k
                    status = (type_info->cls->free_func)(info->u.object, request);
1077
2.84k
                }
1078
2.84k
            H5_AFTER_USER_CB((-1))
1079
1080
2.84k
            if (status >= 0)
1081
2.25k
                remove_node = true;
1082
2.84k
        }
1083
0
        else
1084
0
            remove_node = true;
1085
1086
2.84k
        if (remove_node) {
1087
            /* Remove the node from the type */
1088
2.25k
            if (NULL == H5I__remove_common(type_info, id))
1089
0
                HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, (-1), "can't remove ID node");
1090
2.25k
        } /* end if */
1091
592
        else
1092
592
            ret_value = -1;
1093
2.84k
    } /* end if */
1094
1.44k
    else {
1095
1.44k
        --(info->count);
1096
1.44k
        ret_value = (int)info->count;
1097
1.44k
    } /* end else */
1098
1099
4.28k
done:
1100
4.28k
    FUNC_LEAVE_NOAPI(ret_value)
1101
4.28k
} /* end H5I__dec_ref */
1102
1103
/*-------------------------------------------------------------------------
1104
 * Function:    H5I_dec_ref
1105
 *
1106
 * Purpose:     Decrements the number of references outstanding for an ID.
1107
 *
1108
 * Return:      Success:    New reference count
1109
 *              Failure:    -1
1110
 *
1111
 *-------------------------------------------------------------------------
1112
 */
1113
int
1114
H5I_dec_ref(hid_t id)
1115
3.22k
{
1116
3.22k
    int ret_value = 0; /* Return value */
1117
1118
3.22k
    FUNC_ENTER_NOAPI((-1))
1119
1120
    /* Sanity check */
1121
3.22k
    assert(id >= 0);
1122
1123
    /* Synchronously decrement refcount on ID */
1124
3.22k
    if ((ret_value = H5I__dec_ref(id, H5_REQUEST_NULL)) < 0)
1125
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1126
1127
3.22k
done:
1128
3.22k
    FUNC_LEAVE_NOAPI(ret_value)
1129
3.22k
} /* end H5I_dec_ref() */
1130
1131
/*-------------------------------------------------------------------------
1132
 * Function:    H5I__dec_app_ref
1133
 *
1134
 * Purpose:     Wrapper for case of modifying the application ref.
1135
 *              count for an ID as well as normal reference count.
1136
 *
1137
 * Note:        Allows for asynchronous 'close' operation on object, with
1138
 *              request != H5_REQUEST_NULL.
1139
 *
1140
 * Return:      Success:    New app. reference count
1141
 *              Failure:    -1
1142
 *
1143
 *-------------------------------------------------------------------------
1144
 */
1145
static int
1146
H5I__dec_app_ref(hid_t id, void **request)
1147
1.06k
{
1148
1.06k
    int ret_value = 0; /* Return value */
1149
1150
1.06k
    FUNC_ENTER_PACKAGE
1151
1152
    /* Sanity check */
1153
1.06k
    assert(id >= 0);
1154
1155
    /* Call regular decrement reference count routine */
1156
1.06k
    if ((ret_value = H5I__dec_ref(id, request)) < 0)
1157
592
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1158
1159
    /* Check if the ID still exists */
1160
475
    if (ret_value > 0) {
1161
0
        H5I_id_info_t *info = NULL; /* Pointer to the ID info */
1162
1163
        /* General lookup of the ID */
1164
0
        if (NULL == (info = H5I__find_id(id)))
1165
0
            HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID");
1166
1167
        /* Adjust app_ref */
1168
0
        --(info->app_count);
1169
0
        assert(info->count >= info->app_count);
1170
1171
        /* Set return value */
1172
0
        ret_value = (int)info->app_count;
1173
0
    } /* end if */
1174
1175
1.06k
done:
1176
1.06k
    FUNC_LEAVE_NOAPI(ret_value)
1177
1.06k
} /* end H5I__dec_app_ref() */
1178
1179
/*-------------------------------------------------------------------------
1180
 * Function:    H5I_dec_app_ref
1181
 *
1182
 * Purpose:     Wrapper for case of modifying the application ref. count for
1183
 *              an ID as well as normal reference count.
1184
 *
1185
 * Return:      Success:    New app. reference count
1186
 *              Failure:    -1
1187
 *
1188
 *-------------------------------------------------------------------------
1189
 */
1190
int
1191
H5I_dec_app_ref(hid_t id)
1192
1.02k
{
1193
1.02k
    int ret_value = 0; /* Return value */
1194
1195
1.02k
    FUNC_ENTER_NOAPI((-1))
1196
1197
    /* Sanity check */
1198
1.02k
    assert(id >= 0);
1199
1200
    /* Synchronously decrement refcount on ID */
1201
1.02k
    if ((ret_value = H5I__dec_app_ref(id, H5_REQUEST_NULL)) < 0)
1202
592
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1203
1204
1.02k
done:
1205
1.02k
    FUNC_LEAVE_NOAPI(ret_value)
1206
1.02k
} /* end H5I_dec_app_ref() */
1207
1208
/*-------------------------------------------------------------------------
1209
 * Function:    H5I_dec_app_ref_async
1210
 *
1211
 * Purpose:     Asynchronous wrapper for case of modifying the application ref.
1212
 *              count for an ID as well as normal reference count.
1213
 *
1214
 * Note:        Allows for asynchronous 'close' operation on object, with
1215
 *              token != H5_REQUEST_NULL.
1216
 *
1217
 * Return:      Success:    New app. reference count
1218
 *              Failure:    -1
1219
 *
1220
 *-------------------------------------------------------------------------
1221
 */
1222
int
1223
H5I_dec_app_ref_async(hid_t id, void **token)
1224
0
{
1225
0
    int ret_value = 0; /* Return value */
1226
1227
0
    FUNC_ENTER_NOAPI((-1))
1228
1229
    /* Sanity check */
1230
0
    assert(id >= 0);
1231
1232
    /* [Possibly] asynchronously decrement refcount on ID */
1233
0
    if ((ret_value = H5I__dec_app_ref(id, token)) < 0)
1234
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't asynchronously decrement ID ref count");
1235
1236
0
done:
1237
0
    FUNC_LEAVE_NOAPI(ret_value)
1238
0
} /* end H5I_dec_app_ref_async() */
1239
1240
/*-------------------------------------------------------------------------
1241
 * Function:    H5I__dec_app_ref_always_close
1242
 *
1243
 * Purpose:     Wrapper for case of always closing the ID, even when the free
1244
 *              routine fails
1245
 *
1246
 * Note:        Allows for asynchronous 'close' operation on object, with
1247
 *              request != H5_REQUEST_NULL.
1248
 *
1249
 * Return:      Success:    New app. reference count
1250
 *              Failure:    -1
1251
 *
1252
 *-------------------------------------------------------------------------
1253
 */
1254
static int
1255
H5I__dec_app_ref_always_close(hid_t id, void **request)
1256
39
{
1257
39
    int ret_value = 0; /* Return value */
1258
1259
39
    FUNC_ENTER_PACKAGE
1260
1261
    /* Sanity check */
1262
39
    assert(id >= 0);
1263
1264
    /* Call application decrement reference count routine */
1265
39
    ret_value = H5I__dec_app_ref(id, request);
1266
1267
    /* Check for failure */
1268
39
    if (ret_value < 0) {
1269
        /*
1270
         * If an object is closing, we can remove the ID even though the free
1271
         * method might fail.  This can happen when a mandatory filter fails to
1272
         * write when a dataset is closed and the chunk cache is flushed to the
1273
         * file.  We have to close the dataset anyway. (SLU - 2010/9/7)
1274
         */
1275
0
        H5I_remove(id);
1276
1277
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1278
0
    } /* end if */
1279
1280
39
done:
1281
39
    FUNC_LEAVE_NOAPI(ret_value)
1282
39
} /* end H5I__dec_app_ref_always_close() */
1283
1284
/*-------------------------------------------------------------------------
1285
 * Function:    H5I_dec_app_ref_always_close
1286
 *
1287
 * Purpose:     Wrapper for case of always closing the ID, even when the free
1288
 *              routine fails.
1289
 *
1290
 * Return:      Success:    New app. reference count
1291
 *              Failure:    -1
1292
 *
1293
 *-------------------------------------------------------------------------
1294
 */
1295
int
1296
H5I_dec_app_ref_always_close(hid_t id)
1297
39
{
1298
39
    int ret_value = 0; /* Return value */
1299
1300
39
    FUNC_ENTER_NOAPI((-1))
1301
1302
    /* Sanity check */
1303
39
    assert(id >= 0);
1304
1305
    /* Synchronously decrement refcount on ID */
1306
39
    if ((ret_value = H5I__dec_app_ref_always_close(id, H5_REQUEST_NULL)) < 0)
1307
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1308
1309
39
done:
1310
39
    FUNC_LEAVE_NOAPI(ret_value)
1311
39
} /* end H5I_dec_app_ref_always_close() */
1312
1313
/*-------------------------------------------------------------------------
1314
 * Function:    H5I_dec_app_ref_always_close_async
1315
 *
1316
 * Purpose:     Asynchronous wrapper for case of always closing the ID, even
1317
 *              when the free routine fails
1318
 *
1319
 * Note:        Allows for asynchronous 'close' operation on object, with
1320
 *              token != H5_REQUEST_NULL.
1321
 *
1322
 * Return:      Success:    New app. reference count
1323
 *              Failure:    -1
1324
 *
1325
 *-------------------------------------------------------------------------
1326
 */
1327
int
1328
H5I_dec_app_ref_always_close_async(hid_t id, void **token)
1329
0
{
1330
0
    int ret_value = 0; /* Return value */
1331
1332
0
    FUNC_ENTER_NOAPI((-1))
1333
1334
    /* Sanity check */
1335
0
    assert(id >= 0);
1336
1337
    /* [Possibly] asynchronously decrement refcount on ID */
1338
0
    if ((ret_value = H5I__dec_app_ref_always_close(id, token)) < 0)
1339
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't asynchronously decrement ID ref count");
1340
1341
0
done:
1342
0
    FUNC_LEAVE_NOAPI(ret_value)
1343
0
} /* end H5I_dec_app_ref_always_close_async() */
1344
1345
/*-------------------------------------------------------------------------
1346
 * Function:    H5I_inc_ref
1347
 *
1348
 * Purpose:     Increment the reference count for an object.
1349
 *
1350
 * Return:      Success:    The new reference count
1351
 *              Failure:    -1
1352
 *
1353
 *-------------------------------------------------------------------------
1354
 */
1355
int
1356
H5I_inc_ref(hid_t id, bool app_ref)
1357
1.44k
{
1358
1.44k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID info */
1359
1.44k
    int            ret_value = 0;    /* Return value */
1360
1361
1.44k
    FUNC_ENTER_NOAPI((-1))
1362
1363
    /* Sanity check */
1364
1.44k
    assert(id >= 0);
1365
1366
    /* General lookup of the ID */
1367
1.44k
    if (NULL == (info = H5I__find_id(id)))
1368
0
        HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID");
1369
1370
    /* Adjust reference counts */
1371
1.44k
    ++(info->count);
1372
1.44k
    if (app_ref)
1373
0
        ++(info->app_count);
1374
1375
    /* Set return value */
1376
1.44k
    ret_value = (int)(app_ref ? info->app_count : info->count);
1377
1378
1.44k
done:
1379
1.44k
    FUNC_LEAVE_NOAPI(ret_value)
1380
1.44k
} /* end H5I_inc_ref() */
1381
1382
/*-------------------------------------------------------------------------
1383
 * Function:    H5I_get_ref
1384
 *
1385
 * Purpose:     Retrieve the reference count for an object.
1386
 *
1387
 * Return:      Success:    The reference count
1388
 *              Failure:    -1
1389
 *
1390
 *-------------------------------------------------------------------------
1391
 */
1392
int
1393
H5I_get_ref(hid_t id, bool app_ref)
1394
0
{
1395
0
    H5I_id_info_t *info      = NULL; /* Pointer to the ID */
1396
0
    int            ret_value = 0;    /* Return value */
1397
1398
0
    FUNC_ENTER_NOAPI((-1))
1399
1400
    /* Sanity check */
1401
0
    assert(id >= 0);
1402
1403
    /* General lookup of the ID */
1404
0
    if (NULL == (info = H5I__find_id(id)))
1405
0
        HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID");
1406
1407
    /* Set return value */
1408
0
    ret_value = (int)(app_ref ? info->app_count : info->count);
1409
1410
0
done:
1411
0
    FUNC_LEAVE_NOAPI(ret_value)
1412
0
} /* end H5I_get_ref() */
1413
1414
/*-------------------------------------------------------------------------
1415
 * Function:    H5I__inc_type_ref
1416
 *
1417
 * Purpose:     Increment the reference count for an ID type.
1418
 *
1419
 * Return:      Success:    The new reference count
1420
 *              Failure:    -1
1421
 *
1422
 *-------------------------------------------------------------------------
1423
 */
1424
int
1425
H5I__inc_type_ref(H5I_type_t type)
1426
0
{
1427
0
    H5I_type_info_t *type_info = NULL; /* Pointer to the type */
1428
0
    int              ret_value = -1;   /* Return value */
1429
1430
0
    FUNC_ENTER_PACKAGE
1431
1432
    /* Sanity check */
1433
0
    assert(type > 0 && (int)type < H5I_next_type_g);
1434
1435
    /* Check arguments */
1436
0
    type_info = H5I_type_info_array_g[type];
1437
0
    if (NULL == type_info)
1438
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, (-1), "invalid type");
1439
1440
    /* Set return value */
1441
0
    ret_value = (int)(++(type_info->init_count));
1442
1443
0
done:
1444
0
    FUNC_LEAVE_NOAPI(ret_value)
1445
0
} /* end H5I__inc_type_ref() */
1446
1447
/*-------------------------------------------------------------------------
1448
 * Function:    H5I_dec_type_ref
1449
 *
1450
 * Purpose:     Decrements the reference count on an entire type of IDs.
1451
 *              If the type reference count becomes zero then the type is
1452
 *              destroyed along with all IDs in that type regardless of
1453
 *              their reference counts. Destroying IDs involves calling
1454
 *              the free-func for each ID's object and then adding the ID
1455
 *              struct to the ID free list.
1456
 *              Returns the number of references to the type on success; a
1457
 *              return value of 0 means that the type will have to be
1458
 *              re-initialized before it can be used again (and should probably
1459
 *              be set to H5I_UNINIT).
1460
 *
1461
 * Return:      Success:    Number of references to type
1462
 *              Failure:    -1
1463
 *
1464
 *-------------------------------------------------------------------------
1465
 */
1466
int
1467
H5I_dec_type_ref(H5I_type_t type)
1468
30
{
1469
30
    H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
1470
30
    herr_t           ret_value = 0;    /* Return value */
1471
1472
30
    FUNC_ENTER_NOAPI((-1))
1473
1474
30
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1475
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, (-1), "invalid type number");
1476
1477
30
    type_info = H5I_type_info_array_g[type];
1478
30
    if (type_info == NULL || type_info->init_count <= 0)
1479
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, (-1), "invalid type");
1480
1481
    /* Decrement the number of users of the ID type.  If this is the
1482
     * last user of the type then release all IDs from the type and
1483
     * free all memory it used.  The free function is invoked for each ID
1484
     * being freed.
1485
     */
1486
30
    if (1 == type_info->init_count) {
1487
30
        H5I__destroy_type(type);
1488
30
        ret_value = 0;
1489
30
    }
1490
0
    else {
1491
0
        --(type_info->init_count);
1492
0
        ret_value = (herr_t)type_info->init_count;
1493
0
    }
1494
1495
30
done:
1496
30
    FUNC_LEAVE_NOAPI(ret_value)
1497
30
} /* end H5I_dec_type_ref() */
1498
1499
/*-------------------------------------------------------------------------
1500
 * Function:    H5I__get_type_ref
1501
 *
1502
 * Purpose:     Retrieve the reference count for an ID type.
1503
 *
1504
 * Return:      Success:    The reference count
1505
 *
1506
 *              Failure:    -1
1507
 *
1508
 *-------------------------------------------------------------------------
1509
 */
1510
int
1511
H5I__get_type_ref(H5I_type_t type)
1512
0
{
1513
0
    H5I_type_info_t *type_info = NULL; /* Pointer to the type  */
1514
0
    int              ret_value = -1;   /* Return value         */
1515
1516
0
    FUNC_ENTER_PACKAGE
1517
1518
    /* Sanity check */
1519
0
    assert(type >= 0);
1520
1521
    /* Check arguments */
1522
0
    type_info = H5I_type_info_array_g[type];
1523
0
    if (!type_info)
1524
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, (-1), "invalid type");
1525
1526
    /* Set return value */
1527
0
    ret_value = (int)type_info->init_count;
1528
1529
0
done:
1530
0
    FUNC_LEAVE_NOAPI(ret_value)
1531
0
} /* end H5I__get_type_ref() */
1532
1533
/*-------------------------------------------------------------------------
1534
 * Function:    H5I__iterate_cb
1535
 *
1536
 * Purpose:     Callback routine for H5I_iterate, invokes "user" callback
1537
 *              function, and then sets return value, based on the result of
1538
 *              that callback.
1539
 *
1540
 * Return:      Success:    H5_ITER_CONT (0) or H5_ITER_STOP (1)
1541
 *              Failure:    H5_ITER_ERROR (-1)
1542
 *
1543
 *-------------------------------------------------------------------------
1544
 */
1545
static int
1546
H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
1547
568
{
1548
568
    H5I_id_info_t    *info      = (H5I_id_info_t *)_item;     /* Pointer to the ID info */
1549
568
    H5I_iterate_ud_t *udata     = (H5I_iterate_ud_t *)_udata; /* User data for callback */
1550
568
    int               ret_value = H5_ITER_CONT;               /* Callback return value */
1551
1552
568
    FUNC_ENTER_PACKAGE_NOERR
1553
1554
    /* Only invoke the callback function if this ID is visible externally and
1555
     * its reference count is positive.
1556
     */
1557
568
    if ((!udata->app_ref) || (info->app_count > 0)) {
1558
568
        H5I_type_t type = udata->obj_type;
1559
568
        void      *object;
1560
568
        herr_t     cb_ret_val = FAIL;
1561
1562
        /* The stored object pointer might be an H5VL_object_t, in which
1563
         * case we'll need to get the wrapped object struct (H5F_t *, etc.).
1564
         */
1565
568
        object = H5I__unwrap(info->u.object, type);
1566
1567
        /* Invoke callback function */
1568
        /* Prepare & restore library for user callback */
1569
568
        H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1570
568
            {
1571
568
                cb_ret_val = (*udata->user_func)((void *)object, info->id, udata->user_udata);
1572
568
            }
1573
568
        H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1574
1575
        /* Set the return value based on the callback's return value */
1576
568
        if (cb_ret_val > 0)
1577
0
            ret_value = H5_ITER_STOP; /* terminate iteration early */
1578
568
        else if (cb_ret_val < 0)
1579
0
            ret_value = H5_ITER_ERROR; /* indicate failure (which terminates iteration) */
1580
568
    }
1581
1582
568
    FUNC_LEAVE_NOAPI(ret_value)
1583
568
} /* end H5I__iterate_cb() */
1584
1585
/*-------------------------------------------------------------------------
1586
 * Function:    H5I_iterate
1587
 *
1588
 * Purpose:     Apply function FUNC to each member of type TYPE (with
1589
 *              non-zero application reference count if app_ref is true).
1590
 *              Stop if FUNC returns a non zero value (i.e. anything
1591
 *              other than H5_ITER_CONT).
1592
 *
1593
 *              If FUNC returns a positive value (i.e. H5_ITER_STOP),
1594
 *              return SUCCEED.
1595
 *
1596
 *              If FUNC returns a negative value (i.e. H5_ITER_ERROR),
1597
 *              return FAIL.
1598
 *
1599
 *              The FUNC should take a pointer to the object and the
1600
 *              udata as arguments and return non-zero to terminate
1601
 *              siteration, and zero to continue.
1602
 *
1603
 * Limitation:  Currently there is no way to start the iteration from
1604
 *              where a previous iteration left off.
1605
 *
1606
 * Return:      SUCCEED/FAIL
1607
 *
1608
 *-------------------------------------------------------------------------
1609
 */
1610
herr_t
1611
H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, bool app_ref)
1612
1.07k
{
1613
1.07k
    H5I_type_info_t *type_info = NULL;    /* Pointer to the type */
1614
1.07k
    herr_t           ret_value = SUCCEED; /* Return value */
1615
1616
1.07k
    FUNC_ENTER_NOAPI(FAIL)
1617
1618
    /* Check arguments */
1619
1.07k
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1620
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
1621
1.07k
    type_info = H5I_type_info_array_g[type];
1622
1623
    /* Only iterate through ID list if it is initialized and there are IDs in type */
1624
1.07k
    if (type_info && type_info->init_count > 0 && type_info->id_count > 0) {
1625
4
        H5I_iterate_ud_t iter_udata; /* User data for iteration callback */
1626
4
        H5I_id_info_t   *item = NULL;
1627
4
        H5I_id_info_t   *tmp  = NULL;
1628
1629
        /* Set up iterator user data */
1630
4
        iter_udata.user_func  = func;
1631
4
        iter_udata.user_udata = udata;
1632
4
        iter_udata.app_ref    = app_ref;
1633
4
        iter_udata.obj_type   = type;
1634
1635
        /* Iterate over IDs */
1636
4
        HASH_ITER(hh, type_info->hash_table, item, tmp)
1637
568
        {
1638
568
            if (!item->marked) {
1639
568
                int ret = H5I__iterate_cb((void *)item, NULL, (void *)&iter_udata);
1640
568
                if (H5_ITER_ERROR == ret)
1641
0
                    HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed");
1642
568
                if (H5_ITER_STOP == ret)
1643
0
                    break;
1644
568
            }
1645
568
        }
1646
4
    }
1647
1648
1.07k
done:
1649
1.07k
    FUNC_LEAVE_NOAPI(ret_value)
1650
1.07k
} /* end H5I_iterate() */
1651
1652
/*-------------------------------------------------------------------------
1653
 * Function:    H5I__find_id
1654
 *
1655
 * Purpose:     Given an object ID find the info struct that describes the
1656
 *              object.
1657
 *
1658
 * Return:      Success:    A pointer to the object's info struct.
1659
 *
1660
 *              Failure:    NULL
1661
 *
1662
 *-------------------------------------------------------------------------
1663
 */
1664
H5I_id_info_t *
1665
H5I__find_id(hid_t id)
1666
131k
{
1667
131k
    H5I_type_t       type;             /* ID's type */
1668
131k
    H5I_type_info_t *type_info = NULL; /* Pointer to the type */
1669
131k
    H5I_id_info_t   *id_info   = NULL; /* ID's info */
1670
131k
    H5I_id_info_t   *ret_value = NULL; /* Return value */
1671
1672
131k
    FUNC_ENTER_PACKAGE_NOERR
1673
1674
    /* Check arguments */
1675
131k
    type = H5I_TYPE(id);
1676
131k
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1677
0
        HGOTO_DONE(NULL);
1678
131k
    type_info = H5I_type_info_array_g[type];
1679
131k
    if (!type_info || type_info->init_count <= 0)
1680
0
        HGOTO_DONE(NULL);
1681
1682
    /* Check for same ID as we have looked up last time */
1683
131k
    if (type_info->last_id_info && type_info->last_id_info->id == id)
1684
53.6k
        id_info = type_info->last_id_info;
1685
78.1k
    else {
1686
78.1k
        HASH_FIND(hh, type_info->hash_table, &id, sizeof(hid_t), id_info);
1687
1688
        /* Remember this ID */
1689
78.1k
        type_info->last_id_info = id_info;
1690
78.1k
    }
1691
1692
    /* Check if this is a future ID */
1693
131k
    if (id_info && id_info->is_future) {
1694
0
        hid_t  actual_id = H5I_INVALID_HID; /* ID for actual object */
1695
0
        void  *future_object;               /* Pointer to the future object */
1696
0
        void  *actual_object;               /* Pointer to the actual object */
1697
0
        herr_t status = FAIL;
1698
1699
        /* Prepare & restore library for user callback */
1700
0
        H5_BEFORE_USER_CB_NOERR(NULL)
1701
0
            {
1702
                /* Invoke the realize callback, to get the actual object */
1703
0
                status = (id_info->realize_cb)(id_info->u.object, &actual_id);
1704
0
            }
1705
0
        H5_AFTER_USER_CB_NOERR(NULL)
1706
0
        if (status < 0)
1707
0
            HGOTO_DONE(NULL);
1708
1709
        /* Verify that we received a valid ID, of the same type */
1710
0
        if (H5I_INVALID_HID == actual_id)
1711
0
            HGOTO_DONE(NULL);
1712
0
        if (H5I_TYPE(id) != H5I_TYPE(actual_id))
1713
0
            HGOTO_DONE(NULL);
1714
1715
        /* Swap the actual object in for the future object */
1716
0
        future_object = id_info->u.object;
1717
0
        actual_object = H5I__remove_common(type_info, actual_id);
1718
0
        assert(actual_object);
1719
0
        id_info->u.object = actual_object;
1720
1721
        /* Prepare & restore library for user callback */
1722
0
        H5_BEFORE_USER_CB_NOERR(NULL)
1723
0
            {
1724
                /* Discard the future object */
1725
0
                status = (id_info->discard_cb)(future_object);
1726
0
            }
1727
0
        H5_AFTER_USER_CB_NOERR(NULL)
1728
0
        if (status < 0)
1729
0
            HGOTO_DONE(NULL);
1730
0
        future_object = NULL;
1731
1732
        /* Change the ID from 'future' to 'actual' */
1733
0
        id_info->is_future  = false;
1734
0
        id_info->realize_cb = NULL;
1735
0
        id_info->discard_cb = NULL;
1736
0
    }
1737
1738
    /* Set return value */
1739
131k
    ret_value = id_info;
1740
1741
131k
done:
1742
131k
    FUNC_LEAVE_NOAPI(ret_value)
1743
131k
} /* end H5I__find_id() */
1744
1745
/*-------------------------------------------------------------------------
1746
 * Function:    H5I__find_id_cb
1747
 *
1748
 * Purpose:     Callback for searching for an ID with a specific pointer
1749
 *
1750
 * Return:      Success:    H5_ITER_CONT (0) or H5_ITER_STOP (1)
1751
 *              Failure:    H5_ITER_ERROR (-1)
1752
 *
1753
 *-------------------------------------------------------------------------
1754
 */
1755
static int
1756
H5I__find_id_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
1757
0
{
1758
0
    H5I_id_info_t   *info      = (H5I_id_info_t *)_item;    /* Pointer to the ID info */
1759
0
    H5I_get_id_ud_t *udata     = (H5I_get_id_ud_t *)_udata; /* Pointer to user data */
1760
0
    H5I_type_t       type      = udata->obj_type;
1761
0
    const void      *object    = NULL;
1762
0
    int              ret_value = H5_ITER_CONT; /* Return value */
1763
1764
0
    FUNC_ENTER_PACKAGE_NOERR
1765
1766
    /* Sanity check */
1767
0
    assert(info);
1768
0
    assert(udata);
1769
1770
    /* Get a pointer to the VOL connector's data */
1771
0
    object = H5I__unwrap(info->u.object, type);
1772
1773
    /* Check for a match */
1774
0
    if (object == udata->object) {
1775
0
        udata->ret_id = info->id;
1776
0
        ret_value     = H5_ITER_STOP;
1777
0
    }
1778
1779
0
    FUNC_LEAVE_NOAPI(ret_value)
1780
0
} /* end H5I__find_id_cb() */
1781
1782
/*-------------------------------------------------------------------------
1783
 * Function:    H5I_find_id
1784
 *
1785
 * Purpose:     Return the ID of an object by searching through the ID list
1786
 *              for the type.
1787
 *
1788
 * Return:      SUCCEED/FAIL
1789
 *              (id will be set to H5I_INVALID_HID on errors or not found)
1790
 *
1791
 *-------------------------------------------------------------------------
1792
 */
1793
herr_t
1794
H5I_find_id(const void *object, H5I_type_t type, hid_t *id)
1795
0
{
1796
0
    H5I_type_info_t *type_info = NULL;    /* Pointer to the type */
1797
0
    herr_t           ret_value = SUCCEED; /* Return value */
1798
1799
0
    FUNC_ENTER_NOAPI(FAIL)
1800
1801
0
    assert(id);
1802
1803
0
    *id = H5I_INVALID_HID;
1804
1805
0
    type_info = H5I_type_info_array_g[type];
1806
0
    if (!type_info || type_info->init_count <= 0)
1807
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type");
1808
1809
    /* Only iterate through ID list if it is initialized and there are IDs in type */
1810
0
    if (type_info->init_count > 0 && type_info->id_count > 0) {
1811
0
        H5I_get_id_ud_t udata; /* User data */
1812
0
        H5I_id_info_t  *item = NULL;
1813
0
        H5I_id_info_t  *tmp  = NULL;
1814
1815
        /* Set up iterator user data */
1816
0
        udata.object   = object;
1817
0
        udata.obj_type = type;
1818
0
        udata.ret_id   = H5I_INVALID_HID;
1819
1820
        /* Iterate over IDs for the ID type */
1821
0
        HASH_ITER(hh, type_info->hash_table, item, tmp)
1822
0
        {
1823
0
            int ret = H5I__find_id_cb((void *)item, NULL, (void *)&udata);
1824
0
            if (H5_ITER_ERROR == ret)
1825
0
                HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed");
1826
0
            if (H5_ITER_STOP == ret)
1827
0
                break;
1828
0
        }
1829
1830
0
        *id = udata.ret_id;
1831
0
    }
1832
1833
0
done:
1834
0
    FUNC_LEAVE_NOAPI(ret_value)
1835
0
} /* end H5I_find_id() */