Coverage Report

Created: 2026-03-04 00:50

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
59.0k
#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
2
{
125
2
    int in_use = 0; /* Number of ID types still in use */
126
127
2
    FUNC_ENTER_NOAPI_NOINIT_NOERR
128
129
1
    if (H5_PKG_INIT_VAR) {
130
1
        H5I_type_info_t *type_info = NULL; /* Pointer to ID type */
131
1
        int              i;
132
133
        /* Count the number of types still in use */
134
18
        for (i = 0; i < H5I_next_type_g; i++)
135
17
            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
1
        if (0 == in_use) {
140
18
            for (i = 0; i < H5I_next_type_g; i++) {
141
17
                type_info = H5I_type_info_array_g[i];
142
17
                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
17
            }
149
150
            /* Mark interface closed */
151
1
            if (0 == in_use)
152
1
                H5_PKG_INIT_VAR = false;
153
1
        }
154
1
    }
155
156
1
    FUNC_LEAVE_NOAPI(in_use)
157
2
} /* 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
15
{
243
15
    H5I_type_info_t *type_info = NULL;    /* Pointer to the ID type*/
244
15
    herr_t           ret_value = SUCCEED; /* Return value */
245
246
15
    FUNC_ENTER_NOAPI(FAIL)
247
248
    /* Sanity check */
249
15
    assert(cls);
250
15
    assert(cls->type > 0 && (int)cls->type < H5I_MAX_NUM_TYPES);
251
252
    /* Initialize the type */
253
15
    if (NULL == H5I_type_info_array_g[cls->type]) {
254
        /* Allocate the type information for new type */
255
15
        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
15
        H5I_type_info_array_g[cls->type] = type_info;
258
15
    }
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
15
    if (type_info->init_count == 0) {
266
15
        type_info->cls          = cls;
267
15
        type_info->id_count     = 0;
268
15
        type_info->nextid       = cls->reserved;
269
15
        type_info->last_id_info = NULL;
270
15
        type_info->hash_table   = NULL;
271
15
    }
272
273
    /* Increment the count of the times this type has been initialized */
274
15
    type_info->init_count++;
275
276
15
done:
277
    /* Clean up on error */
278
15
    if (ret_value < 0)
279
0
        if (type_info)
280
0
            H5MM_free(type_info);
281
282
15
    FUNC_LEAVE_NOAPI(ret_value)
283
15
} /* 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
29
{
300
29
    H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
301
29
    int64_t          ret_value = 0;    /* Return value */
302
303
29
    FUNC_ENTER_NOAPI((-1))
304
305
    /* Validate parameter */
306
29
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
307
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
308
29
    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
29
    H5_CHECKED_ASSIGN(ret_value, int64_t, type_info->id_count, uint64_t);
313
314
29
done:
315
29
    FUNC_LEAVE_NOAPI(ret_value)
316
29
} /* 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
3.48k
{
331
3.48k
    void *ret_value = NULL; /* Return value */
332
333
3.48k
    FUNC_ENTER_PACKAGE_NOERR
334
335
    /* Sanity checks */
336
3.48k
    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
3.48k
    if (H5I_FILE == type || H5I_GROUP == type || H5I_DATASET == type || H5I_ATTR == type) {
342
3.08k
        const H5VL_object_t *vol_obj;
343
344
3.08k
        vol_obj   = (const H5VL_object_t *)object;
345
3.08k
        ret_value = H5VL_object_data(vol_obj);
346
3.08k
    }
347
398
    else if (H5I_DATATYPE == type) {
348
217
        H5T_t *dt = (H5T_t *)object;
349
350
217
        ret_value = (void *)H5T_get_actual_type(dt);
351
217
    }
352
181
    else
353
181
        ret_value = object;
354
355
3.48k
    FUNC_LEAVE_NOAPI(ret_value)
356
3.48k
} /* 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
22
{
371
22
    H5I_clear_type_ud_t udata; /* udata struct for callback */
372
22
    H5I_id_info_t      *item      = NULL;
373
22
    H5I_id_info_t      *tmp       = NULL;
374
22
    herr_t              ret_value = SUCCEED; /* Return value */
375
376
22
    FUNC_ENTER_NOAPI(FAIL)
377
378
    /* Validate parameters */
379
22
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
380
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
381
382
22
    udata.type_info = H5I_type_info_array_g[type];
383
22
    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
22
    udata.force   = force;
388
22
    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
22
    H5I_marking_s = true;
397
398
    /* Mark nodes for deletion */
399
22
    HASH_ITER(hh, udata.type_info->hash_table, item, tmp)
400
677
    {
401
677
        if (!item->marked)
402
495
            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
677
    }
405
406
    /* Unset marking flag */
407
22
    H5I_marking_s = false;
408
409
    /* Perform sweep */
410
22
    HASH_ITER(hh, udata.type_info->hash_table, item, tmp)
411
677
    {
412
677
        if (item->marked) {
413
677
            HASH_DELETE(hh, udata.type_info->hash_table, item);
414
677
            item = H5FL_FREE(H5I_id_info_t, item);
415
677
        }
416
677
    }
417
418
22
done:
419
22
    FUNC_LEAVE_NOAPI(ret_value)
420
22
} /* 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
495
{
435
495
    H5I_id_info_t       *info  = (H5I_id_info_t *)_info;        /* Current ID info being worked with */
436
495
    H5I_clear_type_ud_t *udata = (H5I_clear_type_ud_t *)_udata; /* udata struct */
437
495
    bool                 mark  = false;
438
439
495
    FUNC_ENTER_PACKAGE_NOERR
440
441
    /* Sanity checks */
442
495
    assert(info);
443
495
    assert(udata);
444
495
    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
495
    if (udata->force || (info->count - (!udata->app_ref * info->app_count)) <= 1) {
450
        /* Check if this is an un-realized future object */
451
495
        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
495
        else {
473
            /* Check for a 'free' function and call it, if it exists */
474
495
            if (udata->type_info->cls->free_func) {
475
495
                herr_t status;
476
477
                /* Prepare & restore library for user callback */
478
495
                H5_BEFORE_USER_CB_NOCHECK
479
495
                    {
480
495
                        status = (udata->type_info->cls->free_func)(info->u.object, H5_REQUEST_NULL);
481
495
                    }
482
495
                H5_AFTER_USER_CB_NOCHECK
483
495
                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
495
                else
490
                    /* Indicate node should be removed from list */
491
495
                    mark = true;
492
495
            }
493
0
            else {
494
                /* Indicate node should be removed from list */
495
0
                mark = true;
496
0
            }
497
495
        }
498
499
        /* Remove ID if requested */
500
495
        if (mark) {
501
            /* Mark ID for deletion */
502
495
            info->marked = true;
503
504
            /* Decrement the number of IDs in the type */
505
495
            udata->type_info->id_count--;
506
495
        }
507
495
    }
508
509
495
    FUNC_LEAVE_NOAPI(SUCCEED)
510
495
} /* 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
15
{
527
15
    H5I_type_info_t *type_info = NULL;    /* Pointer to the ID type */
528
15
    herr_t           ret_value = SUCCEED; /* Return value */
529
530
15
    FUNC_ENTER_PACKAGE
531
532
    /* Validate parameter */
533
15
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
534
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
535
536
15
    type_info = H5I_type_info_array_g[type];
537
15
    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
15
    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
15
    if (type_info->cls->flags & H5I_CLASS_IS_APPLICATION)
546
0
        type_info->cls = H5MM_xfree_const(type_info->cls);
547
548
15
    HASH_CLEAR(hh, type_info->hash_table);
549
15
    type_info->hash_table = NULL;
550
551
15
    type_info = H5MM_xfree(type_info);
552
553
15
    H5I_type_info_array_g[type] = NULL;
554
555
15
done:
556
15
    FUNC_LEAVE_NOAPI(ret_value)
557
15
} /* 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
59.0k
{
582
59.0k
    H5I_type_info_t *type_info = NULL;            /* Pointer to the type */
583
59.0k
    H5I_id_info_t   *info      = NULL;            /* Pointer to the new ID information */
584
59.0k
    hid_t            new_id    = H5I_INVALID_HID; /* New ID */
585
59.0k
    hid_t            ret_value = H5I_INVALID_HID; /* Return value */
586
587
59.0k
    FUNC_ENTER_PACKAGE
588
589
    /* Check arguments */
590
59.0k
    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
59.0k
    type_info = H5I_type_info_array_g[type];
593
59.0k
    if ((NULL == type_info) || (type_info->init_count <= 0))
594
0
        HGOTO_ERROR(H5E_ID, H5E_BADGROUP, H5I_INVALID_HID, "invalid type");
595
59.0k
    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
59.0k
    new_id           = H5I_MAKE(type, type_info->nextid);
600
59.0k
    info->id         = new_id;
601
59.0k
    info->count      = 1; /* initial reference count */
602
59.0k
    info->app_count  = !!app_ref;
603
59.0k
    info->u.c_object = object;
604
59.0k
    info->is_future  = (NULL != realize_cb);
605
59.0k
    info->realize_cb = realize_cb;
606
59.0k
    info->discard_cb = discard_cb;
607
59.0k
    info->marked     = false;
608
609
    /* Insert into the type */
610
59.0k
    HASH_ADD(hh, type_info->hash_table, id, sizeof(hid_t), info);
611
59.0k
    type_info->id_count++;
612
59.0k
    type_info->nextid++;
613
614
    /* Sanity check for the 'nextid' getting too large and wrapping around */
615
59.0k
    assert(type_info->nextid <= ID_MASK);
616
617
    /* Set the most recent ID to this object */
618
59.0k
    type_info->last_id_info = info;
619
620
    /* Set return value */
621
59.0k
    ret_value = new_id;
622
623
59.0k
done:
624
59.0k
    FUNC_LEAVE_NOAPI(ret_value)
625
59.0k
} /* 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
59.0k
{
640
59.0k
    hid_t ret_value = H5I_INVALID_HID; /* Return value */
641
642
59.0k
    FUNC_ENTER_NOAPI(H5I_INVALID_HID)
643
644
    /* Sanity checks */
645
59.0k
    assert(type >= H5I_FILE && type < H5I_NTYPES);
646
59.0k
    assert(object);
647
648
    /* Retrieve ID for object */
649
59.0k
    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
59.0k
done:
653
59.0k
    FUNC_LEAVE_NOAPI(ret_value)
654
59.0k
} /* 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
54.8k
{
780
54.8k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID info */
781
54.8k
    void          *ret_value = NULL; /* Return value */
782
783
54.8k
    FUNC_ENTER_NOAPI_NOERR
784
785
    /* General lookup of the ID */
786
54.8k
    if (NULL != (info = H5I__find_id(id)))
787
        /* Get the object pointer to return */
788
54.8k
        ret_value = info->u.object;
789
790
54.8k
    FUNC_LEAVE_NOAPI(ret_value)
791
54.8k
} /* 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
221k
{
808
221k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID info */
809
221k
    void          *ret_value = NULL; /* Return value */
810
811
221k
    FUNC_ENTER_NOAPI_NOERR
812
813
221k
    assert(type >= 1 && (int)type < H5I_next_type_g);
814
815
    /* Verify that the type of the ID is correct & lookup the ID */
816
221k
    if (type == H5I_TYPE(id) && NULL != (info = H5I__find_id(id)))
817
        /* Get the object pointer to return */
818
220k
        ret_value = info->u.object;
819
820
221k
    FUNC_LEAVE_NOAPI(ret_value)
821
221k
} /* 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
141k
{
841
141k
    H5I_type_t ret_value = H5I_BADID; /* Return value */
842
843
141k
    FUNC_ENTER_NOAPI_NOERR
844
845
141k
    if (id > 0)
846
140k
        ret_value = H5I_TYPE(id);
847
848
141k
    assert(ret_value >= H5I_BADID && (int)ret_value < H5I_next_type_g);
849
850
141k
    FUNC_LEAVE_NOAPI(ret_value)
851
141k
} /* 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
58.5k
{
945
58.5k
    H5I_id_info_t *info      = NULL; /* Pointer to the current ID */
946
58.5k
    void          *ret_value = NULL; /* Return value */
947
948
58.5k
    FUNC_ENTER_PACKAGE
949
950
    /* Sanity check */
951
58.5k
    assert(type_info);
952
953
    /* Delete or mark the node */
954
58.5k
    HASH_FIND(hh, type_info->hash_table, &id, sizeof(hid_t), info);
955
58.5k
    if (info) {
956
58.5k
        assert(!info->marked);
957
58.5k
        if (!H5I_marking_s)
958
58.5k
            HASH_DELETE(hh, type_info->hash_table, info);
959
182
        else
960
182
            info->marked = true;
961
58.5k
    }
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
58.5k
    if (type_info->last_id_info == info)
967
58.3k
        type_info->last_id_info = NULL;
968
969
58.5k
    ret_value = info->u.object;
970
971
58.5k
    if (!H5I_marking_s)
972
58.3k
        info = H5FL_FREE(H5I_id_info_t, info);
973
974
    /* Decrement the number of IDs in the type */
975
58.5k
    (type_info->id_count)--;
976
977
58.5k
done:
978
58.5k
    FUNC_LEAVE_NOAPI(ret_value)
979
58.5k
} /* 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
181
{
996
181
    H5I_type_info_t *type_info = NULL;      /* Pointer to the ID type */
997
181
    H5I_type_t       type      = H5I_BADID; /* ID's type */
998
181
    void            *ret_value = NULL;      /* Return value */
999
1000
181
    FUNC_ENTER_NOAPI(NULL)
1001
1002
    /* Check arguments */
1003
181
    type = H5I_TYPE(id);
1004
181
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1005
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number");
1006
181
    type_info = H5I_type_info_array_g[type];
1007
181
    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
181
    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
181
done:
1015
181
    FUNC_LEAVE_NOAPI(ret_value)
1016
181
} /* 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
65.8k
{
1037
65.8k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID */
1038
65.8k
    int            ret_value = 0;    /* Return value */
1039
1040
65.8k
    FUNC_ENTER_PACKAGE
1041
1042
    /* Sanity check */
1043
65.8k
    assert(id >= 0);
1044
1045
    /* General lookup of the ID */
1046
65.8k
    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
65.8k
    if (1 == info->count) {
1064
58.3k
        H5I_type_info_t *type_info; /*ptr to the type    */
1065
58.3k
        bool             remove_node = false;
1066
1067
        /* Get the ID's type */
1068
58.3k
        type_info = H5I_type_info_array_g[H5I_TYPE(id)];
1069
1070
58.3k
        if (type_info->cls->free_func) {
1071
58.3k
            herr_t status;
1072
1073
            /* Prepare & restore library for user callback */
1074
58.3k
            H5_BEFORE_USER_CB((-1))
1075
58.3k
                {
1076
58.3k
                    status = (type_info->cls->free_func)(info->u.object, request);
1077
58.3k
                }
1078
58.3k
            H5_AFTER_USER_CB((-1))
1079
1080
58.3k
            if (status >= 0)
1081
58.3k
                remove_node = true;
1082
58.3k
        }
1083
0
        else
1084
0
            remove_node = true;
1085
1086
58.3k
        if (remove_node) {
1087
            /* Remove the node from the type */
1088
58.3k
            if (NULL == H5I__remove_common(type_info, id))
1089
0
                HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, (-1), "can't remove ID node");
1090
58.3k
        } /* end if */
1091
0
        else
1092
0
            ret_value = -1;
1093
58.3k
    } /* end if */
1094
7.47k
    else {
1095
7.47k
        --(info->count);
1096
7.47k
        ret_value = (int)info->count;
1097
7.47k
    } /* end else */
1098
1099
65.8k
done:
1100
65.8k
    FUNC_LEAVE_NOAPI(ret_value)
1101
65.8k
} /* 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
19.6k
{
1116
19.6k
    int ret_value = 0; /* Return value */
1117
1118
19.6k
    FUNC_ENTER_NOAPI((-1))
1119
1120
    /* Sanity check */
1121
19.6k
    assert(id >= 0);
1122
1123
    /* Synchronously decrement refcount on ID */
1124
19.6k
    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
19.6k
done:
1128
19.6k
    FUNC_LEAVE_NOAPI(ret_value)
1129
19.6k
} /* 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
46.1k
{
1148
46.1k
    int ret_value = 0; /* Return value */
1149
1150
46.1k
    FUNC_ENTER_PACKAGE
1151
1152
    /* Sanity check */
1153
46.1k
    assert(id >= 0);
1154
1155
    /* Call regular decrement reference count routine */
1156
46.1k
    if ((ret_value = H5I__dec_ref(id, request)) < 0)
1157
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1158
1159
    /* Check if the ID still exists */
1160
46.1k
    if (ret_value > 0) {
1161
6.04k
        H5I_id_info_t *info = NULL; /* Pointer to the ID info */
1162
1163
        /* General lookup of the ID */
1164
6.04k
        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
6.04k
        --(info->app_count);
1169
6.04k
        assert(info->count >= info->app_count);
1170
1171
        /* Set return value */
1172
6.04k
        ret_value = (int)info->app_count;
1173
6.04k
    } /* end if */
1174
1175
46.1k
done:
1176
46.1k
    FUNC_LEAVE_NOAPI(ret_value)
1177
46.1k
} /* 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
34.4k
{
1193
34.4k
    int ret_value = 0; /* Return value */
1194
1195
34.4k
    FUNC_ENTER_NOAPI((-1))
1196
1197
    /* Sanity check */
1198
34.4k
    assert(id >= 0);
1199
1200
    /* Synchronously decrement refcount on ID */
1201
34.4k
    if ((ret_value = H5I__dec_app_ref(id, H5_REQUEST_NULL)) < 0)
1202
0
        HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count");
1203
1204
34.4k
done:
1205
34.4k
    FUNC_LEAVE_NOAPI(ret_value)
1206
34.4k
} /* 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
11.7k
{
1257
11.7k
    int ret_value = 0; /* Return value */
1258
1259
11.7k
    FUNC_ENTER_PACKAGE
1260
1261
    /* Sanity check */
1262
11.7k
    assert(id >= 0);
1263
1264
    /* Call application decrement reference count routine */
1265
11.7k
    ret_value = H5I__dec_app_ref(id, request);
1266
1267
    /* Check for failure */
1268
11.7k
    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
11.7k
done:
1281
11.7k
    FUNC_LEAVE_NOAPI(ret_value)
1282
11.7k
} /* 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
11.7k
{
1298
11.7k
    int ret_value = 0; /* Return value */
1299
1300
11.7k
    FUNC_ENTER_NOAPI((-1))
1301
1302
    /* Sanity check */
1303
11.7k
    assert(id >= 0);
1304
1305
    /* Synchronously decrement refcount on ID */
1306
11.7k
    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
11.7k
done:
1310
11.7k
    FUNC_LEAVE_NOAPI(ret_value)
1311
11.7k
} /* 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
7.47k
{
1358
7.47k
    H5I_id_info_t *info      = NULL; /* Pointer to the ID info */
1359
7.47k
    int            ret_value = 0;    /* Return value */
1360
1361
7.47k
    FUNC_ENTER_NOAPI((-1))
1362
1363
    /* Sanity check */
1364
7.47k
    assert(id >= 0);
1365
1366
    /* General lookup of the ID */
1367
7.47k
    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
7.47k
    ++(info->count);
1372
7.47k
    if (app_ref)
1373
6.04k
        ++(info->app_count);
1374
1375
    /* Set return value */
1376
7.47k
    ret_value = (int)(app_ref ? info->app_count : info->count);
1377
1378
7.47k
done:
1379
7.47k
    FUNC_LEAVE_NOAPI(ret_value)
1380
7.47k
} /* 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
15
{
1469
15
    H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
1470
15
    herr_t           ret_value = 0;    /* Return value */
1471
1472
15
    FUNC_ENTER_NOAPI((-1))
1473
1474
15
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1475
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, (-1), "invalid type number");
1476
1477
15
    type_info = H5I_type_info_array_g[type];
1478
15
    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
15
    if (1 == type_info->init_count) {
1487
15
        H5I__destroy_type(type);
1488
15
        ret_value = 0;
1489
15
    }
1490
0
    else {
1491
0
        --(type_info->init_count);
1492
0
        ret_value = (herr_t)type_info->init_count;
1493
0
    }
1494
1495
15
done:
1496
15
    FUNC_LEAVE_NOAPI(ret_value)
1497
15
} /* 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
2.15k
{
1548
2.15k
    H5I_id_info_t    *info      = (H5I_id_info_t *)_item;     /* Pointer to the ID info */
1549
2.15k
    H5I_iterate_ud_t *udata     = (H5I_iterate_ud_t *)_udata; /* User data for callback */
1550
2.15k
    int               ret_value = H5_ITER_CONT;               /* Callback return value */
1551
1552
2.15k
    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
2.15k
    if ((!udata->app_ref) || (info->app_count > 0)) {
1558
2.15k
        H5I_type_t type = udata->obj_type;
1559
2.15k
        void      *object;
1560
2.15k
        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
2.15k
        object = H5I__unwrap(info->u.object, type);
1566
1567
        /* Invoke callback function */
1568
        /* Prepare & restore library for user callback */
1569
2.15k
        H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1570
2.15k
            {
1571
2.15k
                cb_ret_val = (*udata->user_func)((void *)object, info->id, udata->user_udata);
1572
2.15k
            }
1573
2.15k
        H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1574
1575
        /* Set the return value based on the callback's return value */
1576
2.15k
        if (cb_ret_val > 0)
1577
877
            ret_value = H5_ITER_STOP; /* terminate iteration early */
1578
1.27k
        else if (cb_ret_val < 0)
1579
0
            ret_value = H5_ITER_ERROR; /* indicate failure (which terminates iteration) */
1580
2.15k
    }
1581
1582
2.15k
    FUNC_LEAVE_NOAPI(ret_value)
1583
2.15k
} /* 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
7.94k
{
1613
7.94k
    H5I_type_info_t *type_info = NULL;    /* Pointer to the type */
1614
7.94k
    herr_t           ret_value = SUCCEED; /* Return value */
1615
1616
7.94k
    FUNC_ENTER_NOAPI(FAIL)
1617
1618
    /* Check arguments */
1619
7.94k
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1620
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number");
1621
7.94k
    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
7.94k
    if (type_info && type_info->init_count > 0 && type_info->id_count > 0) {
1625
1.75k
        H5I_iterate_ud_t iter_udata; /* User data for iteration callback */
1626
1.75k
        H5I_id_info_t   *item = NULL;
1627
1.75k
        H5I_id_info_t   *tmp  = NULL;
1628
1629
        /* Set up iterator user data */
1630
1.75k
        iter_udata.user_func  = func;
1631
1.75k
        iter_udata.user_udata = udata;
1632
1.75k
        iter_udata.app_ref    = app_ref;
1633
1.75k
        iter_udata.obj_type   = type;
1634
1635
        /* Iterate over IDs */
1636
1.75k
        HASH_ITER(hh, type_info->hash_table, item, tmp)
1637
2.15k
        {
1638
2.15k
            if (!item->marked) {
1639
2.15k
                int ret = H5I__iterate_cb((void *)item, NULL, (void *)&iter_udata);
1640
2.15k
                if (H5_ITER_ERROR == ret)
1641
0
                    HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed");
1642
2.15k
                if (H5_ITER_STOP == ret)
1643
877
                    break;
1644
2.15k
            }
1645
2.15k
        }
1646
1.75k
    }
1647
1648
7.94k
done:
1649
7.94k
    FUNC_LEAVE_NOAPI(ret_value)
1650
7.94k
} /* 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
354k
{
1667
354k
    H5I_type_t       type;             /* ID's type */
1668
354k
    H5I_type_info_t *type_info = NULL; /* Pointer to the type */
1669
354k
    H5I_id_info_t   *id_info   = NULL; /* ID's info */
1670
354k
    H5I_id_info_t   *ret_value = NULL; /* Return value */
1671
1672
354k
    FUNC_ENTER_PACKAGE_NOERR
1673
1674
    /* Check arguments */
1675
354k
    type = H5I_TYPE(id);
1676
354k
    if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
1677
0
        HGOTO_DONE(NULL);
1678
354k
    type_info = H5I_type_info_array_g[type];
1679
354k
    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
354k
    if (type_info->last_id_info && type_info->last_id_info->id == id)
1684
236k
        id_info = type_info->last_id_info;
1685
117k
    else {
1686
117k
        HASH_FIND(hh, type_info->hash_table, &id, sizeof(hid_t), id_info);
1687
1688
        /* Remember this ID */
1689
117k
        type_info->last_id_info = id_info;
1690
117k
    }
1691
1692
    /* Check if this is a future ID */
1693
354k
    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
354k
    ret_value = id_info;
1740
1741
354k
done:
1742
354k
    FUNC_LEAVE_NOAPI(ret_value)
1743
354k
} /* 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
1.33k
{
1758
1.33k
    H5I_id_info_t   *info      = (H5I_id_info_t *)_item;    /* Pointer to the ID info */
1759
1.33k
    H5I_get_id_ud_t *udata     = (H5I_get_id_ud_t *)_udata; /* Pointer to user data */
1760
1.33k
    H5I_type_t       type      = udata->obj_type;
1761
1.33k
    const void      *object    = NULL;
1762
1.33k
    int              ret_value = H5_ITER_CONT; /* Return value */
1763
1764
1.33k
    FUNC_ENTER_PACKAGE_NOERR
1765
1766
    /* Sanity check */
1767
1.33k
    assert(info);
1768
1.33k
    assert(udata);
1769
1770
    /* Get a pointer to the VOL connector's data */
1771
1.33k
    object = H5I__unwrap(info->u.object, type);
1772
1773
    /* Check for a match */
1774
1.33k
    if (object == udata->object) {
1775
1.33k
        udata->ret_id = info->id;
1776
1.33k
        ret_value     = H5_ITER_STOP;
1777
1.33k
    }
1778
1779
1.33k
    FUNC_LEAVE_NOAPI(ret_value)
1780
1.33k
} /* 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
1.33k
{
1796
1.33k
    H5I_type_info_t *type_info = NULL;    /* Pointer to the type */
1797
1.33k
    herr_t           ret_value = SUCCEED; /* Return value */
1798
1799
1.33k
    FUNC_ENTER_NOAPI(FAIL)
1800
1801
1.33k
    assert(id);
1802
1803
1.33k
    *id = H5I_INVALID_HID;
1804
1805
1.33k
    type_info = H5I_type_info_array_g[type];
1806
1.33k
    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
1.33k
    if (type_info->init_count > 0 && type_info->id_count > 0) {
1811
1.33k
        H5I_get_id_ud_t udata; /* User data */
1812
1.33k
        H5I_id_info_t  *item = NULL;
1813
1.33k
        H5I_id_info_t  *tmp  = NULL;
1814
1815
        /* Set up iterator user data */
1816
1.33k
        udata.object   = object;
1817
1.33k
        udata.obj_type = type;
1818
1.33k
        udata.ret_id   = H5I_INVALID_HID;
1819
1820
        /* Iterate over IDs for the ID type */
1821
1.33k
        HASH_ITER(hh, type_info->hash_table, item, tmp)
1822
1.33k
        {
1823
1.33k
            int ret = H5I__find_id_cb((void *)item, NULL, (void *)&udata);
1824
1.33k
            if (H5_ITER_ERROR == ret)
1825
0
                HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed");
1826
1.33k
            if (H5_ITER_STOP == ret)
1827
1.33k
                break;
1828
1.33k
        }
1829
1830
1.33k
        *id = udata.ret_id;
1831
1.33k
    }
1832
1833
1.33k
done:
1834
1.33k
    FUNC_LEAVE_NOAPI(ret_value)
1835
1.33k
} /* end H5I_find_id() */