Coverage Report

Created: 2025-08-29 07:09

/src/hdf5/src/H5ESint.c
Line
Count
Source (jump to first uncovered line)
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
 *
15
 * Created:     H5ESint.c
16
 *
17
 * Purpose:     Internal "event set" routines for managing asynchronous
18
 *                      operations.
19
 *
20
 *                      Please see the asynchronous I/O RFC document
21
 *                      for a full description of how they work, etc.
22
 *
23
 *-------------------------------------------------------------------------
24
 */
25
26
/****************/
27
/* Module Setup */
28
/****************/
29
30
#include "H5ESmodule.h" /* This source code file is part of the H5ES module */
31
32
/***********/
33
/* Headers */
34
/***********/
35
#include "H5private.h"   /* Generic Functions      */
36
#include "H5Eprivate.h"  /* Error handling         */
37
#include "H5ESpkg.h"     /* Event Sets                           */
38
#include "H5FLprivate.h" /* Free Lists                           */
39
#include "H5Iprivate.h"  /* IDs                                  */
40
#include "H5MMprivate.h" /* Memory management                    */
41
#include "H5RSprivate.h" /* Reference-counted strings            */
42
#include "H5VLprivate.h" /* Virtual Object Layer                 */
43
44
/****************/
45
/* Local Macros */
46
/****************/
47
48
/******************/
49
/* Local Typedefs */
50
/******************/
51
52
/* Callback context for get events operations */
53
typedef struct H5ES_get_requests_ctx_t {
54
    hid_t *connector_ids; /* Output buffer for list of connector IDs that match the above requests */
55
    void **requests;      /* Output buffer for list of requests in event set */
56
    size_t array_len;     /* Length of the above output buffers */
57
    size_t i;             /* Number of elements filled in output buffers */
58
} H5ES_get_requests_ctx_t;
59
60
/* Callback context for wait operations */
61
typedef struct H5ES_wait_ctx_t {
62
    H5ES_t  *es;              /* Event set being operated on */
63
    uint64_t timeout;         /* Timeout for wait operation (in ns) */
64
    size_t  *num_in_progress; /* Count of # of operations that have not completed */
65
    bool    *op_failed;       /* Flag to indicate an operation failed */
66
} H5ES_wait_ctx_t;
67
68
/* Callback context for cancel operations */
69
typedef struct H5ES_cancel_ctx_t {
70
    H5ES_t *es;               /* Event set being operated on */
71
    size_t *num_not_canceled; /* Count of # of operations were not canceled */
72
    bool   *op_failed;        /* Flag to indicate an operation failed */
73
} H5ES_cancel_ctx_t;
74
75
/* Callback context for get error info (gei) operations */
76
typedef struct H5ES_gei_ctx_t {
77
    H5ES_t          *es;            /* Event set being operated on */
78
    size_t           num_err_info;  /* # of elements in err_info[] array */
79
    size_t           curr_err;      /* Index of current error in array */
80
    H5ES_err_info_t *curr_err_info; /* Pointer to current element in err_info[] array */
81
} H5ES_gei_ctx_t;
82
83
/********************/
84
/* Package Typedefs */
85
/********************/
86
87
/********************/
88
/* Local Prototypes */
89
/********************/
90
static herr_t H5ES__close(H5ES_t *es);
91
static herr_t H5ES__close_cb(void *es, void **request_token);
92
static herr_t H5ES__insert(H5ES_t *es, H5VL_connector_t *connector, void *request_token, const char *app_file,
93
                           const char *app_func, unsigned app_line, const char *caller, const char *api_args);
94
static int    H5ES__get_requests_cb(H5ES_event_t *ev, void *_ctx);
95
static herr_t H5ES__handle_fail(H5ES_t *es, H5ES_event_t *ev);
96
static herr_t H5ES__op_complete(H5ES_t *es, H5ES_event_t *ev, H5VL_request_status_t ev_status);
97
static int    H5ES__wait_cb(H5ES_event_t *ev, void *_ctx);
98
static int    H5ES__cancel_cb(H5ES_event_t *ev, void *_ctx);
99
static int    H5ES__get_err_info_cb(H5ES_event_t *ev, void *_ctx);
100
static int    H5ES__close_failed_cb(H5ES_event_t *ev, void *_ctx);
101
102
/*********************/
103
/* Package Variables */
104
/*********************/
105
106
/* Package initialization variable */
107
bool H5_PKG_INIT_VAR = false;
108
109
/*****************************/
110
/* Library Private Variables */
111
/*****************************/
112
113
/*******************/
114
/* Local Variables */
115
/*******************/
116
117
/* Event Set ID class */
118
static const H5I_class_t H5I_EVENTSET_CLS[1] = {{
119
    H5I_EVENTSET,              /* ID class value */
120
    0,                         /* Class flags */
121
    0,                         /* # of reserved IDs for class */
122
    (H5I_free_t)H5ES__close_cb /* Callback routine for closing objects of this class */
123
}};
124
125
/* Declare a static free list to manage H5ES_t structs */
126
H5FL_DEFINE_STATIC(H5ES_t);
127
128
/*-------------------------------------------------------------------------
129
 * Function:    H5ES__init_package
130
 *
131
 * Purpose:     Initializes any interface-specific data or routines.
132
 *
133
 * Return:      Non-negative on success / Negative on failure
134
 *
135
 * Purpose:     Initialize the interface from some other layer.
136
 *
137
 *-------------------------------------------------------------------------
138
 */
139
herr_t
140
H5ES__init_package(void)
141
0
{
142
0
    herr_t ret_value = SUCCEED; /* Return value */
143
144
0
    FUNC_ENTER_PACKAGE
145
146
    /* Initialize the ID group for the event set IDs */
147
0
    if (H5I_register_type(H5I_EVENTSET_CLS) < 0)
148
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTINIT, FAIL, "unable to initialize interface");
149
150
0
done:
151
0
    FUNC_LEAVE_NOAPI(ret_value)
152
0
} /* end H5ES__init_package() */
153
154
/*-------------------------------------------------------------------------
155
 * Function:    H5ES_term_package
156
 *
157
 * Purpose:     Terminate this interface.
158
 *
159
 * Return:      Success:    Positive if anything is done that might
160
 *                          affect other interfaces; zero otherwise.
161
 *              Failure:    Negative
162
 *
163
 *-------------------------------------------------------------------------
164
 */
165
int
166
H5ES_term_package(void)
167
101
{
168
101
    int n = 0;
169
170
101
    FUNC_ENTER_NOAPI_NOINIT_NOERR
171
172
0
    if (H5_PKG_INIT_VAR) {
173
        /* Destroy the event set ID group */
174
0
        n += (H5I_dec_type_ref(H5I_EVENTSET) > 0);
175
176
        /* Mark closed */
177
0
        if (0 == n)
178
0
            H5_PKG_INIT_VAR = false;
179
0
    } /* end if */
180
181
0
    FUNC_LEAVE_NOAPI(n)
182
101
} /* end H5ES_term_package() */
183
184
/*-------------------------------------------------------------------------
185
 * Function:    H5ES__close_cb
186
 *
187
 * Purpose:     Called when the ref count reaches zero on an event set's ID
188
 *
189
 * Return:      SUCCEED / FAIL
190
 *
191
 *-------------------------------------------------------------------------
192
 */
193
static herr_t
194
H5ES__close_cb(void *_es, void H5_ATTR_UNUSED **rt)
195
0
{
196
0
    H5ES_t *es        = (H5ES_t *)_es; /* The event set to close */
197
0
    herr_t  ret_value = SUCCEED;       /* Return value */
198
199
0
    FUNC_ENTER_PACKAGE
200
201
    /* Sanity check */
202
0
    assert(es);
203
204
    /* Close the event set object */
205
0
    if (H5ES__close(es) < 0)
206
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CLOSEERROR, FAIL, "unable to close event set");
207
208
0
done:
209
0
    FUNC_LEAVE_NOAPI(ret_value)
210
0
} /* end H5ES__close_cb() */
211
212
/*-------------------------------------------------------------------------
213
 * Function:    H5ES__create
214
 *
215
 * Purpose:     Private function to create an event set object
216
 *
217
 * Return:      Success:    Pointer to an event set struct
218
 *              Failure:    NULL
219
 *
220
 *-------------------------------------------------------------------------
221
 */
222
H5ES_t *
223
H5ES__create(void)
224
0
{
225
0
    H5ES_t *es        = NULL; /* Pointer to event set */
226
0
    H5ES_t *ret_value = NULL; /* Return value */
227
228
0
    FUNC_ENTER_PACKAGE
229
230
    /* Allocate space for new event set */
231
0
    if (NULL == (es = H5FL_CALLOC(H5ES_t)))
232
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, NULL, "can't allocate event set object");
233
234
    /* Set the return value */
235
0
    ret_value = es;
236
237
0
done:
238
0
    if (!ret_value)
239
0
        if (es && H5ES__close(es) < 0)
240
0
            HDONE_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, NULL, "unable to free event set");
241
242
0
    FUNC_LEAVE_NOAPI(ret_value)
243
0
} /* end H5ES__create() */
244
245
/*-------------------------------------------------------------------------
246
 * Function:    H5ES__insert
247
 *
248
 * Purpose:     Insert a request token into an event set
249
 *
250
 * Return:      SUCCEED / FAIL
251
 *
252
 *-------------------------------------------------------------------------
253
 */
254
static herr_t
255
H5ES__insert(H5ES_t *es, H5VL_connector_t *connector, void *request_token, const char *app_file,
256
             const char *app_func, unsigned app_line, const char *caller, const char *api_args)
257
0
{
258
0
    H5ES_event_t *ev          = NULL;    /* Event for request */
259
0
    bool          ev_inserted = false;   /* Flag to indicate that event is in active list */
260
0
    herr_t        ret_value   = SUCCEED; /* Return value */
261
262
0
    FUNC_ENTER_PACKAGE
263
264
    /* Sanity check */
265
0
    assert(es);
266
267
    /* Create new event */
268
0
    if (NULL == (ev = H5ES__event_new(connector, request_token)))
269
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTCREATE, FAIL, "can't create event object");
270
271
    /* Copy the app source information */
272
    /* The 'app_func' & 'app_file' strings are statically allocated (by the compiler)
273
     * there's no need to duplicate them.
274
     */
275
0
    ev->op_info.app_file_name = app_file;
276
0
    ev->op_info.app_func_name = app_func;
277
0
    ev->op_info.app_line_num  = app_line;
278
279
    /* Set the event's operation counter */
280
0
    ev->op_info.op_ins_count = es->op_counter++;
281
282
    /* Set the event's timestamp & execution time */
283
0
    ev->op_info.op_ins_ts    = H5_now_usec();
284
0
    ev->op_info.op_exec_ts   = UINT64_MAX;
285
0
    ev->op_info.op_exec_time = UINT64_MAX;
286
287
    /* Copy the API routine's name & arguments */
288
    /* The 'caller' string is also statically allocated (by the compiler)
289
     * there's no need to duplicate it.
290
     */
291
0
    ev->op_info.api_name = caller;
292
0
    assert(ev->op_info.api_args == NULL);
293
0
    if (api_args && NULL == (ev->op_info.api_args = H5MM_xstrdup(api_args)))
294
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, FAIL, "can't copy API routine arguments");
295
296
    /* Append fully initialized event onto the event set's 'active' list */
297
0
    H5ES__list_append(&es->active, ev);
298
0
    ev_inserted = true;
299
300
    /* Invoke the event set's 'insert' callback, if present */
301
0
    if (es->ins_func) {
302
0
        int status = -1;
303
304
        /* Prepare & restore library for user callback */
305
0
        H5_BEFORE_USER_CB(FAIL)
306
0
            {
307
0
                status = (es->ins_func)(&ev->op_info, es->ins_ctx);
308
0
            }
309
0
        H5_AFTER_USER_CB(FAIL)
310
0
        if (status < 0)
311
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CALLBACK, FAIL, "'insert' callback for event set failed");
312
0
    }
313
314
0
done:
315
    /* Release resources on error */
316
0
    if (ret_value < 0)
317
0
        if (ev) {
318
0
            if (ev_inserted)
319
0
                H5ES__list_remove(&es->active, ev);
320
0
            if (H5ES__event_free(ev) < 0)
321
0
                HDONE_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, FAIL, "unable to release event");
322
0
        }
323
324
0
    FUNC_LEAVE_NOAPI(ret_value)
325
0
} /* end H5ES__insert() */
326
327
/*-------------------------------------------------------------------------
328
 * Function:    H5ES_insert
329
 *
330
 * Purpose:     Insert a request token into an event set
331
 *
332
 * Return:      SUCCEED / FAIL
333
 *
334
 *-------------------------------------------------------------------------
335
 */
336
herr_t
337
H5ES_insert(hid_t es_id, H5VL_connector_t *connector, void *token, const char *caller,
338
            const char *caller_args, ...)
339
0
{
340
0
    H5ES_t     *es = NULL;             /* Event set for the operation */
341
0
    const char *app_file;              /* Application source file name */
342
0
    const char *app_func;              /* Application source function name */
343
0
    unsigned    app_line;              /* Application source line number */
344
0
    H5RS_str_t *rs = NULL;             /* Ref-counted string to compose formatted argument string in */
345
0
    const char *api_args;              /* Pointer to api_args string from ref-counted string */
346
0
    va_list     ap;                    /* Varargs for caller */
347
0
    bool        arg_started = false;   /* Whether the va_list has been started */
348
0
    herr_t      ret_value   = SUCCEED; /* Return value */
349
350
0
    FUNC_ENTER_NOAPI(FAIL)
351
352
    /* Sanity check */
353
0
    assert(connector);
354
0
    assert(token);
355
0
    assert(caller);
356
0
    assert(caller_args);
357
358
    /* Get event set */
359
0
    if (NULL == (es = (H5ES_t *)H5I_object_verify(es_id, H5I_EVENTSET)))
360
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an event set");
361
362
    /* Check for errors in event set */
363
0
    if (es->err_occurred)
364
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTINSERT, FAIL, "event set has failed operations");
365
366
    /* Start working on the API routines arguments */
367
0
    va_start(ap, caller_args);
368
0
    arg_started = true;
369
370
    /* Copy the app source information */
371
0
    (void)va_arg(ap, char *); /* Toss the 'app_file' parameter name */
372
0
    app_file = va_arg(ap, char *);
373
0
    (void)va_arg(ap, char *); /* Toss the 'app_func' parameter name */
374
0
    app_func = va_arg(ap, char *);
375
0
    (void)va_arg(ap, char *); /* Toss the 'app_line' parameter name */
376
0
    app_line = va_arg(ap, unsigned);
377
378
    /* Create the string for the API routine's arguments */
379
0
    if (NULL == (rs = H5RS_create(NULL)))
380
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, FAIL, "can't allocate ref-counted string");
381
382
    /* Copy the string for the API routine's arguments */
383
    /* (skip the six characters from the app's file, function and line # arguments) */
384
0
    assert(0 == strncmp(caller_args, "*s*sIu", 6));
385
0
    if (H5_trace_args(rs, caller_args + 6, ap) < 0)
386
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTSET, FAIL, "can't create formatted API arguments");
387
0
    if (NULL == (api_args = H5RS_get_str(rs)))
388
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTGET, FAIL, "can't get pointer to formatted API arguments");
389
390
    /* Insert the operation into the event set */
391
0
    if (H5ES__insert(es, connector, token, app_file, app_func, app_line, caller, api_args) < 0)
392
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTINSERT, FAIL, "event set has failed operations");
393
394
0
done:
395
    /* Clean up */
396
0
    if (arg_started)
397
0
        va_end(ap);
398
0
    if (rs)
399
0
        H5RS_decr(rs);
400
401
0
    FUNC_LEAVE_NOAPI(ret_value)
402
0
} /* end H5ES_insert() */
403
404
/*-------------------------------------------------------------------------
405
 * Function:    H5ES__insert_request
406
 *
407
 * Purpose:     Directly insert a request token into an event set
408
 *
409
 * Return:      SUCCEED / FAIL
410
 *
411
 *-------------------------------------------------------------------------
412
 */
413
herr_t
414
H5ES__insert_request(H5ES_t *es, H5VL_connector_t *connector, void *token)
415
0
{
416
0
    herr_t ret_value = SUCCEED; /* Return value */
417
418
0
    FUNC_ENTER_PACKAGE
419
420
    /* Sanity check */
421
0
    assert(es);
422
0
    assert(connector);
423
0
    assert(token);
424
425
    /* Insert an 'anonymous' operation into the event set */
426
0
    if (H5ES__insert(es, connector, token, NULL, NULL, 0, NULL, NULL) < 0)
427
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTINSERT, FAIL, "event set has failed operations");
428
429
0
done:
430
0
    FUNC_LEAVE_NOAPI(ret_value)
431
0
} /* end H5ES__insert_request() */
432
433
/*-------------------------------------------------------------------------
434
 * Function:    H5ES__get_requests_cb
435
 *
436
 * Purpose:     Iterator callback for H5ES__get_events - adds the event to
437
 *              the list.
438
 *
439
 * Return:      SUCCEED / FAIL
440
 *
441
 *-------------------------------------------------------------------------
442
 */
443
static int
444
H5ES__get_requests_cb(H5ES_event_t *ev, void *_ctx)
445
0
{
446
0
    H5ES_get_requests_ctx_t *ctx       = (H5ES_get_requests_ctx_t *)_ctx; /* Callback context */
447
0
    int                      ret_value = H5_ITER_CONT;                    /* Return value */
448
449
0
    FUNC_ENTER_PACKAGE
450
451
    /* Sanity check */
452
0
    assert(ev);
453
0
    assert(ctx);
454
0
    assert(ctx->i < ctx->array_len);
455
456
    /* Get the connector ID for the event */
457
0
    if (ctx->connector_ids)
458
0
        if ((ctx->connector_ids[ctx->i] = H5VL_conn_register(H5VL_OBJ_CONNECTOR(ev->request))) < 0)
459
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTREGISTER, H5_ITER_ERROR, "unable to register VOL connector ID");
460
461
    /* Get the request for the event */
462
0
    if (ctx->requests)
463
0
        ctx->requests[ctx->i] = H5VL_OBJ_DATA(ev->request);
464
465
    /* Check if we've run out of room in the arrays */
466
0
    if (++ctx->i == ctx->array_len)
467
0
        ret_value = H5_ITER_STOP;
468
469
0
done:
470
0
    FUNC_LEAVE_NOAPI(ret_value)
471
0
} /* end H5ES__get_requests_cb() */
472
473
/*-------------------------------------------------------------------------
474
 * Function:    H5ES__get_requests
475
 *
476
 * Purpose:     Get all requests in an event set.
477
 *
478
 * Return:      SUCCEED / FAIL
479
 *
480
 *-------------------------------------------------------------------------
481
 */
482
herr_t
483
H5ES__get_requests(H5ES_t *es, H5_iter_order_t order, hid_t *connector_ids, void **requests, size_t array_len)
484
0
{
485
0
    H5ES_get_requests_ctx_t ctx;                 /* Callback context */
486
0
    herr_t                  ret_value = SUCCEED; /* Return value */
487
488
0
    FUNC_ENTER_PACKAGE
489
490
    /* Sanity check */
491
0
    assert(es);
492
0
    assert(array_len > 0);
493
0
    assert(requests || connector_ids);
494
495
    /* Set up context for iterator callbacks */
496
0
    ctx.connector_ids = connector_ids;
497
0
    ctx.requests      = requests;
498
0
    ctx.array_len     = array_len;
499
0
    ctx.i             = 0;
500
501
    /* Iterate over the events in the set */
502
0
    if (H5ES__list_iterate(&es->active, order, H5ES__get_requests_cb, &ctx) < 0)
503
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADITER, FAIL, "iteration failed");
504
505
0
done:
506
0
    FUNC_LEAVE_NOAPI(ret_value)
507
0
} /* end H5ES__get_requests() */
508
509
/*-------------------------------------------------------------------------
510
 * Function:    H5ES__handle_fail
511
 *
512
 * Purpose:     Handle a failed event
513
 *
514
 * Return:      SUCCEED / FAIL
515
 *
516
 *-------------------------------------------------------------------------
517
 */
518
static herr_t
519
H5ES__handle_fail(H5ES_t *es, H5ES_event_t *ev)
520
0
{
521
0
    FUNC_ENTER_PACKAGE_NOERR
522
523
    /* Sanity check */
524
0
    assert(es);
525
0
    assert(es->active.head);
526
0
    assert(ev);
527
528
    /* Set error flag for event set */
529
0
    es->err_occurred = true;
530
531
    /* Remove event from normal list */
532
0
    H5ES__list_remove(&es->active, ev);
533
534
    /* Append event onto the event set's error list */
535
0
    H5ES__list_append(&es->failed, ev);
536
537
0
    FUNC_LEAVE_NOAPI(SUCCEED)
538
0
} /* end H5ES__handle_fail() */
539
540
/*-------------------------------------------------------------------------
541
 * Function:    H5ES__op_complete
542
 *
543
 * Purpose:     Handle an operation completing
544
 *
545
 * Return:      SUCCEED / FAIL
546
 *
547
 *-------------------------------------------------------------------------
548
 */
549
static herr_t
550
H5ES__op_complete(H5ES_t *es, H5ES_event_t *ev, H5VL_request_status_t ev_status)
551
0
{
552
0
    H5VL_request_specific_args_t vol_cb_args;                    /* Arguments to VOL callback */
553
0
    hid_t                        err_stack_id = H5I_INVALID_HID; /* Error stack for failed operation */
554
0
    herr_t                       ret_value    = SUCCEED;         /* Return value */
555
556
0
    FUNC_ENTER_PACKAGE
557
558
    /* Sanity check */
559
0
    assert(es);
560
0
    assert(ev);
561
0
    assert(H5VL_REQUEST_STATUS_SUCCEED == ev_status || H5VL_REQUEST_STATUS_FAIL == ev_status ||
562
0
           H5VL_REQUEST_STATUS_CANCELED == ev_status);
563
564
    /* Handle each form of event completion */
565
0
    if (H5VL_REQUEST_STATUS_SUCCEED == ev_status || H5VL_REQUEST_STATUS_CANCELED == ev_status) {
566
        /* Invoke the event set's 'complete' callback, if present */
567
0
        if (es->comp_func) {
568
0
            H5ES_status_t op_status; /* Status for complete callback */
569
0
            int           status = -1;
570
571
            /* Set appropriate info for callback */
572
0
            if (H5VL_REQUEST_STATUS_SUCCEED == ev_status) {
573
                /* Translate status */
574
0
                op_status = H5ES_STATUS_SUCCEED;
575
576
                /* Set up VOL callback arguments */
577
0
                vol_cb_args.op_type                      = H5VL_REQUEST_GET_EXEC_TIME;
578
0
                vol_cb_args.args.get_exec_time.exec_ts   = &ev->op_info.op_exec_ts;
579
0
                vol_cb_args.args.get_exec_time.exec_time = &ev->op_info.op_exec_time;
580
581
                /* Retrieve the execution time info */
582
0
                if (H5VL_request_specific(ev->request, &vol_cb_args) < 0)
583
0
                    HGOTO_ERROR(H5E_EVENTSET, H5E_CANTGET, FAIL,
584
0
                                "unable to retrieve execution time info for operation");
585
0
            }
586
0
            else
587
                /* Translate status */
588
0
                op_status = H5ES_STATUS_CANCELED;
589
590
            /* Prepare & restore library for user callback */
591
0
            H5_BEFORE_USER_CB(FAIL)
592
0
                {
593
0
                    status = (es->comp_func)(&ev->op_info, op_status, H5I_INVALID_HID, es->comp_ctx);
594
0
                }
595
0
            H5_AFTER_USER_CB(FAIL)
596
0
            if (status < 0)
597
0
                HGOTO_ERROR(H5E_EVENTSET, H5E_CALLBACK, FAIL, "'complete' callback for event set failed");
598
0
        } /* end if */
599
600
        /* Event success or cancellation */
601
0
        if (H5ES__event_completed(ev, &es->active) < 0)
602
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, FAIL, "unable to release completed event");
603
0
    } /* end if */
604
0
    else if (H5VL_REQUEST_STATUS_FAIL == ev_status) {
605
        /* Invoke the event set's 'complete' callback, if present */
606
0
        if (es->comp_func) {
607
            /* Set up VOL callback arguments */
608
0
            vol_cb_args.op_type                         = H5VL_REQUEST_GET_ERR_STACK;
609
0
            vol_cb_args.args.get_err_stack.err_stack_id = H5I_INVALID_HID;
610
0
            int status                                  = -1;
611
612
            /* Retrieve the error stack for the operation */
613
0
            if (H5VL_request_specific(ev->request, &vol_cb_args) < 0)
614
0
                HGOTO_ERROR(H5E_EVENTSET, H5E_CANTGET, FAIL, "unable to retrieve error stack for operation");
615
616
            /* Set values */
617
0
            err_stack_id = vol_cb_args.args.get_err_stack.err_stack_id;
618
619
            /* Prepare & restore library for user callback */
620
0
            H5_BEFORE_USER_CB(FAIL)
621
0
                {
622
0
                    status = (es->comp_func)(&ev->op_info, H5ES_STATUS_FAIL, err_stack_id, es->comp_ctx);
623
0
                }
624
0
            H5_AFTER_USER_CB(FAIL)
625
0
            if (status < 0)
626
0
                HGOTO_ERROR(H5E_EVENTSET, H5E_CALLBACK, FAIL, "'complete' callback for event set failed");
627
0
        } /* end if */
628
629
        /* Handle failure */
630
0
        if (H5ES__handle_fail(es, ev) < 0)
631
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTSET, FAIL, "unable to handle failed event");
632
0
    } /* end else-if */
633
0
    else
634
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADVALUE, FAIL, "unknown event status?!?");
635
636
0
done:
637
    /* Clean up */
638
0
    if (H5I_INVALID_HID != err_stack_id)
639
0
        if (H5I_dec_ref(err_stack_id) < 0)
640
0
            HDONE_ERROR(H5E_EVENTSET, H5E_CANTDEC, FAIL,
641
0
                        "unable to decrement ref count on error stack for failed operation")
642
643
0
    FUNC_LEAVE_NOAPI(ret_value)
644
0
} /* end H5ES__op_complete() */
645
646
/*-------------------------------------------------------------------------
647
 * Function:    H5ES__wait_cb
648
 *
649
 * Purpose:     Common routine for testing / waiting on an operation
650
 *
651
 * Return:      SUCCEED / FAIL
652
 *
653
 *-------------------------------------------------------------------------
654
 */
655
static int
656
H5ES__wait_cb(H5ES_event_t *ev, void *_ctx)
657
0
{
658
0
    H5ES_wait_ctx_t      *ctx       = (H5ES_wait_ctx_t *)_ctx;     /* Callback context */
659
0
    H5VL_request_status_t ev_status = H5VL_REQUEST_STATUS_SUCCEED; /* Status from event's operation */
660
0
    uint64_t start_time = 0, elapsed_time = 0; /* Start and elapsed times for waiting on an operation */
661
0
    int      ret_value = H5_ITER_CONT;         /* Return value */
662
663
0
    FUNC_ENTER_PACKAGE
664
665
    /* Sanity check */
666
0
    assert(ev);
667
0
    assert(ctx);
668
669
    /* Wait on the request */
670
0
    if (ctx->timeout != H5ES_WAIT_NONE && ctx->timeout != H5ES_WAIT_FOREVER)
671
0
        start_time = H5_now_usec();
672
0
    if (H5VL_request_wait(ev->request, ctx->timeout, &ev_status) < 0)
673
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTWAIT, H5_ITER_ERROR, "unable to test operation");
674
0
    if (ctx->timeout != H5ES_WAIT_NONE && ctx->timeout != H5ES_WAIT_FOREVER)
675
0
        elapsed_time = H5_now_usec() - start_time;
676
677
    /* Check for status values that indicate we should break out of the loop */
678
0
    if (ev_status == H5VL_REQUEST_STATUS_FAIL) {
679
        /* Handle event completion */
680
0
        if (H5ES__op_complete(ctx->es, ev, ev_status) < 0)
681
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, H5_ITER_ERROR, "unable to release completed event");
682
683
        /* Record the error */
684
0
        *ctx->op_failed = true;
685
686
        /* Exit from the iteration */
687
0
        ret_value = H5_ITER_STOP;
688
0
    } /* end if */
689
0
    else if (ev_status == H5VL_REQUEST_STATUS_SUCCEED || ev_status == H5VL_REQUEST_STATUS_CANCELED) {
690
        /* Handle event completion */
691
0
        if (H5ES__op_complete(ctx->es, ev, ev_status) < 0)
692
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, H5_ITER_ERROR, "unable to release completed event");
693
0
    } /* end else-if */
694
0
    else if (ev_status == H5VL_REQUEST_STATUS_CANT_CANCEL)
695
        /* Should never get a status of 'can't cancel' back from test / wait operation */
696
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADVALUE, H5_ITER_ERROR,
697
0
                    "received \"can't cancel\" status for operation");
698
0
    else {
699
        /* Sanity check */
700
0
        assert(ev_status == H5VL_REQUEST_STATUS_IN_PROGRESS);
701
702
        /* Increment "in progress operation" counter */
703
0
        (*ctx->num_in_progress)++;
704
0
    } /* end if */
705
706
    /* Check for updateable timeout */
707
0
    if (ctx->timeout != H5ES_WAIT_NONE && ctx->timeout != H5ES_WAIT_FOREVER) {
708
        /* Update timeout for next operation */
709
0
        if ((elapsed_time * 1000) > ctx->timeout)
710
0
            ctx->timeout = H5ES_WAIT_NONE;
711
0
        else
712
0
            ctx->timeout -= (elapsed_time * 1000); /* Convert us to ns */
713
0
    }                                              /* end if */
714
715
0
done:
716
0
    FUNC_LEAVE_NOAPI(ret_value)
717
0
} /* end H5ES__wait_cb() */
718
719
/*-------------------------------------------------------------------------
720
 * Function:    H5ES__wait
721
 *
722
 * Purpose:     Wait for operations in event set to complete
723
 *
724
 * Note:        Timeout value is in ns, and is for H5ES__wait itself.
725
 *
726
 * Return:      SUCCEED / FAIL
727
 *
728
 *-------------------------------------------------------------------------
729
 */
730
herr_t
731
H5ES__wait(H5ES_t *es, uint64_t timeout, size_t *num_in_progress, bool *op_failed)
732
0
{
733
0
    H5ES_wait_ctx_t ctx;                 /* Iterator callback context info */
734
0
    herr_t          ret_value = SUCCEED; /* Return value */
735
736
0
    FUNC_ENTER_PACKAGE
737
738
    /* Sanity check */
739
0
    assert(es);
740
0
    assert(num_in_progress);
741
0
    assert(op_failed);
742
743
    /* Set user's parameters to known values */
744
0
    *num_in_progress = 0;
745
0
    *op_failed       = false;
746
747
    /* Set up context for iterator callbacks */
748
0
    ctx.es              = es;
749
0
    ctx.timeout         = timeout;
750
0
    ctx.num_in_progress = num_in_progress;
751
0
    ctx.op_failed       = op_failed;
752
753
    /* Iterate over the events in the set, waiting for them to complete */
754
0
    if (H5ES__list_iterate(&es->active, H5_ITER_NATIVE, H5ES__wait_cb, &ctx) < 0)
755
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADITER, FAIL, "iteration failed");
756
757
0
done:
758
0
    FUNC_LEAVE_NOAPI(ret_value)
759
0
} /* end H5ES__wait() */
760
761
/*-------------------------------------------------------------------------
762
 * Function:    H5ES__cancel_cb
763
 *
764
 * Purpose:     Callback for canceling operations
765
 *
766
 * Return:      SUCCEED / FAIL
767
 *
768
 *-------------------------------------------------------------------------
769
 */
770
static int
771
H5ES__cancel_cb(H5ES_event_t *ev, void *_ctx)
772
0
{
773
0
    H5ES_cancel_ctx_t    *ctx       = (H5ES_cancel_ctx_t *)_ctx;   /* Callback context */
774
0
    H5VL_request_status_t ev_status = H5VL_REQUEST_STATUS_SUCCEED; /* Status from event's operation */
775
0
    int                   ret_value = H5_ITER_CONT;                /* Return value */
776
777
0
    FUNC_ENTER_PACKAGE
778
779
    /* Sanity check */
780
0
    assert(ev);
781
0
    assert(ctx);
782
783
    /* Attempt to cancel the request */
784
0
    if (H5VL_request_cancel(ev->request, &ev_status) < 0)
785
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTCANCEL, H5_ITER_ERROR, "unable to cancel operation");
786
787
    /* Check for status values that indicate we should break out of the loop */
788
0
    if (ev_status == H5VL_REQUEST_STATUS_FAIL) {
789
        /* Handle event completion */
790
0
        if (H5ES__op_complete(ctx->es, ev, ev_status) < 0)
791
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTSET, H5_ITER_ERROR, "unable to handle failed event");
792
793
        /* Record the error */
794
0
        *ctx->op_failed = true;
795
796
        /* Exit from the iteration */
797
0
        ret_value = H5_ITER_STOP;
798
0
    } /* end if */
799
0
    else if (ev_status == H5VL_REQUEST_STATUS_SUCCEED) {
800
        /* Increment "not canceled" counter */
801
0
        (*ctx->num_not_canceled)++;
802
803
        /* Handle event completion */
804
0
        if (H5ES__op_complete(ctx->es, ev, ev_status) < 0)
805
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, H5_ITER_ERROR, "unable to release completed event");
806
0
    } /* end else-if */
807
0
    else if (ev_status == H5VL_REQUEST_STATUS_CANT_CANCEL || ev_status == H5VL_REQUEST_STATUS_IN_PROGRESS) {
808
        /* Increment "not canceled" counter */
809
0
        (*ctx->num_not_canceled)++;
810
0
    } /* end else-if */
811
0
    else {
812
        /* Sanity check */
813
0
        assert(ev_status == H5VL_REQUEST_STATUS_CANCELED);
814
815
        /* Handle event completion */
816
0
        if (H5ES__op_complete(ctx->es, ev, ev_status) < 0)
817
0
            HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, H5_ITER_ERROR, "unable to release completed event");
818
0
    } /* end else */
819
820
0
done:
821
0
    FUNC_LEAVE_NOAPI(ret_value)
822
0
} /* end H5ES__cancel_cb() */
823
824
/*-------------------------------------------------------------------------
825
 * Function:    H5ES__cancel
826
 *
827
 * Purpose:     Cancel operations in event set
828
 *
829
 * Return:      SUCCEED / FAIL
830
 *
831
 *-------------------------------------------------------------------------
832
 */
833
herr_t
834
H5ES__cancel(H5ES_t *es, size_t *num_not_canceled, bool *op_failed)
835
0
{
836
0
    H5ES_cancel_ctx_t ctx;                 /* Iterator callback context info */
837
0
    herr_t            ret_value = SUCCEED; /* Return value */
838
839
0
    FUNC_ENTER_PACKAGE
840
841
    /* Sanity check */
842
0
    assert(es);
843
0
    assert(num_not_canceled);
844
0
    assert(op_failed);
845
846
    /* Set user's parameters to known values */
847
0
    *num_not_canceled = 0;
848
0
    *op_failed        = false;
849
850
    /* Set up context for iterator callbacks */
851
0
    ctx.es               = es;
852
0
    ctx.num_not_canceled = num_not_canceled;
853
0
    ctx.op_failed        = op_failed;
854
855
    /* Iterate over the events in the set, attempting to cancel them */
856
0
    if (H5ES__list_iterate(&es->active, H5_ITER_NATIVE, H5ES__cancel_cb, &ctx) < 0)
857
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADITER, FAIL, "iteration failed");
858
859
0
done:
860
0
    FUNC_LEAVE_NOAPI(ret_value)
861
0
} /* end H5ES__cancel() */
862
863
/*-------------------------------------------------------------------------
864
 * Function:    H5ES__get_err_info_cb
865
 *
866
 * Purpose:     Retrieve information about a failed operation
867
 *
868
 * Return:      SUCCEED / FAIL
869
 *
870
 *-------------------------------------------------------------------------
871
 */
872
static int
873
H5ES__get_err_info_cb(H5ES_event_t *ev, void *_ctx)
874
0
{
875
0
    H5VL_request_specific_args_t vol_cb_args;                        /* Arguments to VOL callback */
876
0
    H5ES_gei_ctx_t              *ctx       = (H5ES_gei_ctx_t *)_ctx; /* Callback context */
877
0
    int                          ret_value = H5_ITER_CONT;           /* Return value */
878
879
0
    FUNC_ENTER_PACKAGE
880
881
    /* Sanity check */
882
0
    assert(ev);
883
0
    assert(ctx);
884
885
    /* Copy operation info for event */
886
    /* The 'app_func_name', 'app_file_name', and 'api_name' strings are statically allocated (by the compiler)
887
     * so there's no need to duplicate them internally, but they are duplicated
888
     * here, when they are given back to the user.
889
     */
890
0
    if (NULL == (ctx->curr_err_info->api_name = H5MM_xstrdup(ev->op_info.api_name)))
891
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, H5_ITER_ERROR, "can't copy HDF5 API routine name");
892
0
    if (NULL == (ctx->curr_err_info->api_args = H5MM_xstrdup(ev->op_info.api_args)))
893
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, H5_ITER_ERROR, "can't copy HDF5 API routine arguments");
894
0
    if (NULL == (ctx->curr_err_info->app_file_name = H5MM_xstrdup(ev->op_info.app_file_name)))
895
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, H5_ITER_ERROR, "can't copy HDF5 application file name");
896
0
    if (NULL == (ctx->curr_err_info->app_func_name = H5MM_xstrdup(ev->op_info.app_func_name)))
897
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTALLOC, H5_ITER_ERROR, "can't copy HDF5 application function name");
898
0
    ctx->curr_err_info->app_line_num = ev->op_info.app_line_num;
899
0
    ctx->curr_err_info->op_ins_count = ev->op_info.op_ins_count;
900
0
    ctx->curr_err_info->op_ins_ts    = ev->op_info.op_ins_ts;
901
0
    ctx->curr_err_info->op_exec_ts   = ev->op_info.op_exec_ts;
902
0
    ctx->curr_err_info->op_exec_time = ev->op_info.op_exec_time;
903
904
    /* Set up VOL callback arguments */
905
0
    vol_cb_args.op_type                         = H5VL_REQUEST_GET_ERR_STACK;
906
0
    vol_cb_args.args.get_err_stack.err_stack_id = H5I_INVALID_HID;
907
908
    /* Get error stack for event */
909
0
    if (H5VL_request_specific(ev->request, &vol_cb_args) < 0)
910
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTGET, H5_ITER_ERROR, "unable to retrieve error stack for operation");
911
912
    /* Set value */
913
0
    ctx->curr_err_info->err_stack_id = vol_cb_args.args.get_err_stack.err_stack_id;
914
915
    /* Remove event from event set's failed list */
916
0
    H5ES__list_remove(&ctx->es->failed, ev);
917
918
    /* Free event node */
919
0
    if (H5ES__event_free(ev) < 0)
920
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, H5_ITER_ERROR, "unable to release failed event");
921
922
    /* Advance to next element of err_info[] array */
923
0
    ctx->curr_err++;
924
0
    ctx->curr_err_info++;
925
926
    /* Stop iteration if err_info[] array is full */
927
0
    if (ctx->curr_err == ctx->num_err_info)
928
0
        ret_value = H5_ITER_STOP;
929
930
0
done:
931
0
    FUNC_LEAVE_NOAPI(ret_value)
932
0
} /* end H5ES__get_err_info_cb() */
933
934
/*-------------------------------------------------------------------------
935
 * Function:    H5ES__get_err_info
936
 *
937
 * Purpose:     Retrieve information about failed operations
938
 *
939
 * Return:      SUCCEED / FAIL
940
 *
941
 *-------------------------------------------------------------------------
942
 */
943
herr_t
944
H5ES__get_err_info(H5ES_t *es, size_t num_err_info, H5ES_err_info_t err_info[], size_t *num_cleared)
945
0
{
946
0
    H5ES_gei_ctx_t ctx;                 /* Iterator callback context info */
947
0
    herr_t         ret_value = SUCCEED; /* Return value */
948
949
0
    FUNC_ENTER_PACKAGE
950
951
    /* Sanity check */
952
0
    assert(es);
953
0
    assert(num_err_info);
954
0
    assert(err_info);
955
0
    assert(num_cleared);
956
957
    /* Set up context for iterator callbacks */
958
0
    ctx.es            = es;
959
0
    ctx.num_err_info  = num_err_info;
960
0
    ctx.curr_err      = 0;
961
0
    ctx.curr_err_info = &err_info[0];
962
963
    /* Iterate over the failed events in the set, copying their error info */
964
0
    if (H5ES__list_iterate(&es->failed, H5_ITER_NATIVE, H5ES__get_err_info_cb, &ctx) < 0)
965
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADITER, FAIL, "iteration failed");
966
967
    /* Set # of failed events cleared from event set's failed list */
968
0
    *num_cleared = ctx.curr_err;
969
970
0
done:
971
0
    FUNC_LEAVE_NOAPI(ret_value)
972
0
} /* end H5ES__get_err_info() */
973
974
/*-------------------------------------------------------------------------
975
 * Function:    H5ES__close_failed_cb
976
 *
977
 * Purpose:     Release a failed event
978
 *
979
 * Return:      SUCCEED / FAIL
980
 *
981
 *-------------------------------------------------------------------------
982
 */
983
static int
984
H5ES__close_failed_cb(H5ES_event_t *ev, void *_ctx)
985
0
{
986
0
    H5ES_t *es        = (H5ES_t *)_ctx; /* Callback context */
987
0
    int     ret_value = H5_ITER_CONT;   /* Return value */
988
989
0
    FUNC_ENTER_PACKAGE
990
991
    /* Sanity check */
992
0
    assert(ev);
993
0
    assert(es);
994
995
    /* Remove event from event set's failed list */
996
0
    H5ES__list_remove(&es->failed, ev);
997
998
    /* Free event node */
999
0
    if (H5ES__event_free(ev) < 0)
1000
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_CANTRELEASE, H5_ITER_ERROR, "unable to release failed event");
1001
1002
0
done:
1003
0
    FUNC_LEAVE_NOAPI(ret_value)
1004
0
} /* end H5ES__close_failed_cb() */
1005
1006
/*-------------------------------------------------------------------------
1007
 * Function:    H5ES__close
1008
 *
1009
 * Purpose:     Destroy an event set object
1010
 *
1011
 * Return:      SUCCEED / FAIL
1012
 *
1013
 *-------------------------------------------------------------------------
1014
 */
1015
herr_t
1016
H5ES__close(H5ES_t *es)
1017
0
{
1018
0
    herr_t ret_value = SUCCEED; /* Return value */
1019
1020
0
    FUNC_ENTER_PACKAGE
1021
1022
    /* Sanity check */
1023
0
    assert(es);
1024
1025
    /* Fail if active operations still present */
1026
0
    if (H5ES__list_count(&es->active) > 0)
1027
0
        HGOTO_ERROR(
1028
0
            H5E_EVENTSET, H5E_CANTCLOSEOBJ, FAIL,
1029
0
            "can't close event set while unfinished operations are present (i.e. wait on event set first)");
1030
1031
    /* Iterate over the failed events in the set, releasing them */
1032
0
    if (H5ES__list_iterate(&es->failed, H5_ITER_NATIVE, H5ES__close_failed_cb, (void *)es) < 0)
1033
0
        HGOTO_ERROR(H5E_EVENTSET, H5E_BADITER, FAIL, "iteration failed");
1034
1035
    /* Release the event set */
1036
0
    es = H5FL_FREE(H5ES_t, es);
1037
1038
0
done:
1039
0
    FUNC_LEAVE_NOAPI(ret_value)
1040
0
} /* end H5ES__close() */