300 lines
15 KiB
C
300 lines
15 KiB
C
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
|
/*
|
|
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
|
* University Research and Technology
|
|
* Corporation. All rights reserved.
|
|
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
|
* of Tennessee Research Foundation. All rights
|
|
* reserved.
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
* University of Stuttgart. All rights reserved.
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
* All rights reserved.
|
|
* Copyright (c) 2015-2020 Intel, Inc. All rights reserved.
|
|
* Copyright (c) 2020 IBM Corporation. All rights reserved.
|
|
* Copyright (c) 2021-2022 Nanook Consulting. All rights reserved.
|
|
* $COPYRIGHT$
|
|
*
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*/
|
|
|
|
#ifndef PMIX_EVENT_H
|
|
#define PMIX_EVENT_H
|
|
|
|
#include "src/include/pmix_config.h"
|
|
#include "src/include/pmix_types.h"
|
|
#include <event.h>
|
|
|
|
#include "pmix_common.h"
|
|
#include "src/class/pmix_list.h"
|
|
#include "src/mca/bfrops/bfrops_types.h"
|
|
#include "src/util/pmix_output.h"
|
|
|
|
BEGIN_C_DECLS
|
|
|
|
#define PMIX_EVENT_ORDER_NONE 0x00
|
|
#define PMIX_EVENT_ORDER_FIRST 0x01
|
|
#define PMIX_EVENT_ORDER_LAST 0x02
|
|
#define PMIX_EVENT_ORDER_BEFORE 0x04
|
|
#define PMIX_EVENT_ORDER_AFTER 0x08
|
|
#define PMIX_EVENT_ORDER_PREPEND 0x10
|
|
#define PMIX_EVENT_ORDER_APPEND 0x20
|
|
#define PMIX_EVENT_ORDER_FIRST_OVERALL 0x40
|
|
#define PMIX_EVENT_ORDER_LAST_OVERALL 0x80
|
|
|
|
/* define an internal attribute for marking that the
|
|
* server processed an event before passing it up
|
|
* to its host in case it comes back down - avoids
|
|
* infinite loop */
|
|
#define PMIX_SERVER_INTERNAL_NOTIFY "pmix.srvr.internal.notify"
|
|
|
|
/* define a struct for tracking registration ranges */
|
|
typedef struct {
|
|
pmix_data_range_t range;
|
|
pmix_proc_t *procs;
|
|
size_t nprocs;
|
|
} pmix_range_trkr_t;
|
|
|
|
#define PMIX_RANGE_TRKR_STATIC_INIT \
|
|
{ \
|
|
.range = PMIX_RANGE_UNDEF, \
|
|
.procs = NULL, \
|
|
.nprocs = 0 \
|
|
}
|
|
|
|
|
|
/* define a common struct for tracking event handlers */
|
|
typedef struct {
|
|
pmix_list_item_t super;
|
|
char *name;
|
|
size_t index;
|
|
uint8_t precedence;
|
|
bool oneshot;
|
|
char *locator;
|
|
pmix_proc_t source; // who generated this event
|
|
/* When registering for events, callers can specify
|
|
* the range of sources from which they are willing
|
|
* to receive notifications - e.g., for callers to
|
|
* define different handlers for events coming from
|
|
* the RM vs those coming from their peers. We use
|
|
* the rng field to track these values upon registration.
|
|
*/
|
|
pmix_range_trkr_t rng;
|
|
/* For registration, we use the affected field to track
|
|
* the range of procs that, if affected by the event,
|
|
* should cause the handler to be called (subject, of
|
|
* course, to any rng constraints).
|
|
*/
|
|
pmix_proc_t *affected;
|
|
size_t naffected;
|
|
pmix_notification_fn_t evhdlr;
|
|
void *cbobject;
|
|
pmix_status_t *codes;
|
|
size_t ncodes;
|
|
} pmix_event_hdlr_t;
|
|
PMIX_CLASS_DECLARATION(pmix_event_hdlr_t);
|
|
|
|
#define PMIX_EVENT_HDLR_STATIC_INIT \
|
|
{ \
|
|
.super = PMIX_LIST_ITEM_STATIC_INIT, \
|
|
.name = NULL, \
|
|
.index = SIZE_MAX, \
|
|
.precedence = UINT8_MAX, \
|
|
.locator = NULL, \
|
|
.source = PMIX_PROC_STATIC_INIT, \
|
|
.rng = PMIX_RANGE_TRKR_STATIC_INIT, \
|
|
.affected - NULL, \
|
|
.naffected = 0, \
|
|
.evhdlr = NULL, \
|
|
.cbobject = NULL, \
|
|
.codes = NULL, \
|
|
.ncodes = 0 \
|
|
}
|
|
|
|
/* define an object for tracking status codes we are actively
|
|
* registered to receive */
|
|
typedef struct {
|
|
pmix_list_item_t super;
|
|
pmix_status_t code;
|
|
size_t nregs;
|
|
} pmix_active_code_t;
|
|
PMIX_CLASS_DECLARATION(pmix_active_code_t);
|
|
|
|
/* define an object for housing the different lists of events
|
|
* we have registered so we can easily scan them in precedent
|
|
* order when we get an event */
|
|
typedef struct {
|
|
pmix_object_t super;
|
|
size_t nhdlrs;
|
|
pmix_event_hdlr_t *first;
|
|
pmix_event_hdlr_t *last;
|
|
pmix_list_t actives;
|
|
pmix_list_t single_events;
|
|
pmix_list_t multi_events;
|
|
pmix_list_t default_events;
|
|
} pmix_events_t;
|
|
PMIX_CLASS_DECLARATION(pmix_events_t);
|
|
|
|
#define PMIX_EVENTS_STATIC_INIT \
|
|
{ \
|
|
.super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \
|
|
.nhdlrs = 0, \
|
|
.first = NULL, \
|
|
.last = NULL, \
|
|
.actives = PMIX_LIST_STATIC_INIT, \
|
|
.single_events = PMIX_LIST_STATIC_INIT, \
|
|
.multi_events = PMIX_LIST_STATIC_INIT, \
|
|
.default_events = PMIX_LIST_STATIC_INIT \
|
|
}
|
|
|
|
/* define an object for chaining event notifications thru
|
|
* the local state machine. Each registered event handler
|
|
* that asked to be notified for a given code is given a
|
|
* chance to "see" the reported event, starting with
|
|
* single-code handlers, then multi-code handlers, and
|
|
* finally default handlers. This object provides a
|
|
* means for us to relay the event across that chain
|
|
*/
|
|
typedef struct pmix_event_chain_t {
|
|
pmix_list_item_t super;
|
|
pmix_status_t status;
|
|
pmix_event_t ev;
|
|
bool timer_active;
|
|
bool nondefault;
|
|
bool endchain;
|
|
bool cached;
|
|
pmix_proc_t source;
|
|
pmix_data_range_t range;
|
|
/* When generating events, callers can specify
|
|
* the range of targets to receive notifications.
|
|
*/
|
|
pmix_proc_t *targets;
|
|
size_t ntargets;
|
|
/* the processes that we affected by the event */
|
|
pmix_proc_t *affected;
|
|
size_t naffected;
|
|
/* any info provided by the event generator */
|
|
pmix_info_t *info;
|
|
size_t ninfo;
|
|
size_t nallocated;
|
|
pmix_status_t interim_status;
|
|
pmix_info_t *results;
|
|
size_t nresults;
|
|
pmix_info_t *interim;
|
|
size_t ninterim;
|
|
pmix_event_hdlr_t *evhdlr;
|
|
pmix_op_cbfunc_t opcbfunc;
|
|
void *cbdata;
|
|
pmix_op_cbfunc_t final_cbfunc;
|
|
void *final_cbdata;
|
|
} pmix_event_chain_t;
|
|
PMIX_CLASS_DECLARATION(pmix_event_chain_t);
|
|
|
|
/* prepare a chain for processing by cycling across provided
|
|
* info structs and translating those supported by the event
|
|
* system into the chain object*/
|
|
PMIX_EXPORT pmix_status_t pmix_prep_event_chain(pmix_event_chain_t *chain, const pmix_info_t *info,
|
|
size_t ninfo, bool xfer);
|
|
|
|
/* invoke the error handler that is registered against the given
|
|
* status, passing it the provided info on the procs that were
|
|
* affected, plus any additional info provided by the server */
|
|
PMIX_EXPORT void pmix_invoke_local_event_hdlr(pmix_event_chain_t *chain);
|
|
|
|
PMIX_EXPORT bool pmix_notify_check_range(pmix_range_trkr_t *rng, const pmix_proc_t *proc);
|
|
|
|
PMIX_EXPORT bool pmix_notify_check_affected(pmix_proc_t *interested, size_t ninterested,
|
|
pmix_proc_t *affected, size_t naffected);
|
|
|
|
PMIX_EXPORT pmix_status_t pmix_deregister_event_hdlr(size_t event_hdlr_ref,
|
|
pmix_buffer_t *msg);
|
|
|
|
/* invoke the server event notification handler */
|
|
PMIX_EXPORT pmix_status_t pmix_server_notify_client_of_event(pmix_status_t status,
|
|
const pmix_proc_t *source,
|
|
pmix_data_range_t range,
|
|
const pmix_info_t info[], size_t ninfo,
|
|
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
|
PMIX_EXPORT pmix_status_t pmix_notify_server_of_event(pmix_status_t status, const pmix_proc_t *source,
|
|
pmix_data_range_t range, const pmix_info_t info[],
|
|
size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata,
|
|
bool dolocal);
|
|
|
|
PMIX_EXPORT void pmix_event_timeout_cb(int fd, short flags, void *arg);
|
|
|
|
#define PMIX_REPORT_EVENT(e, p, r, f) \
|
|
do { \
|
|
pmix_event_chain_t *ch, *cp; \
|
|
size_t _n; \
|
|
\
|
|
ch = NULL; \
|
|
/* see if we already have this event cached */ \
|
|
PMIX_LIST_FOREACH (cp, &pmix_globals.cached_events, pmix_event_chain_t) { \
|
|
if (cp->status == (e)) { \
|
|
ch = cp; \
|
|
break; \
|
|
} \
|
|
} \
|
|
if (NULL == ch) { \
|
|
/* nope - need to add it */ \
|
|
ch = PMIX_NEW(pmix_event_chain_t); \
|
|
ch->status = (e); \
|
|
ch->range = (r); \
|
|
PMIX_LOAD_PROCID(&ch->source, (p)->nptr->nspace, (p)->info->pname.rank); \
|
|
PMIX_PROC_CREATE(ch->affected, 1); \
|
|
ch->naffected = 1; \
|
|
PMIX_LOAD_PROCID(ch->affected, (p)->nptr->nspace, (p)->info->pname.rank); \
|
|
/* if this is lost-connection-to-server, then we let it go to */ \
|
|
/* the default event handler - otherwise, we don't */ \
|
|
if (PMIX_ERR_LOST_CONNECTION != (e) && PMIX_ERR_UNREACH != (e)) { \
|
|
ch->ninfo = 1; \
|
|
ch->nallocated = 3; \
|
|
PMIX_INFO_CREATE(ch->info, ch->nallocated); \
|
|
/* mark for non-default handlers only */ \
|
|
PMIX_INFO_LOAD(&ch->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); \
|
|
} else { \
|
|
ch->nallocated = 2; \
|
|
PMIX_INFO_CREATE(ch->info, ch->nallocated); \
|
|
} \
|
|
ch->final_cbfunc = (f); \
|
|
ch->final_cbdata = ch; \
|
|
/* cache it */ \
|
|
pmix_list_append(&pmix_globals.cached_events, &ch->super); \
|
|
ch->timer_active = true; \
|
|
pmix_event_assign(&ch->ev, pmix_globals.evbase, -1, 0, pmix_event_timeout_cb, ch); \
|
|
PMIX_POST_OBJECT(ch); \
|
|
pmix_event_add(&ch->ev, &pmix_globals.event_window); \
|
|
} else { \
|
|
/* add this peer to the array of sources */ \
|
|
pmix_proc_t proc_tmp; \
|
|
pmix_info_t *info_tmp; \
|
|
size_t ninfo_tmp; \
|
|
pmix_strncpy(proc_tmp.nspace, (p)->nptr->nspace, PMIX_MAX_NSLEN); \
|
|
proc_tmp.rank = (p)->info->pname.rank; \
|
|
ninfo_tmp = ch->nallocated + 1; \
|
|
PMIX_INFO_CREATE(info_tmp, ninfo_tmp); \
|
|
/* must keep the hdlr name and return object at the end, so prepend */ \
|
|
PMIX_INFO_LOAD(&info_tmp[0], PMIX_PROCID, &proc_tmp, PMIX_PROC); \
|
|
for (_n = 0; _n < ch->ninfo; _n++) { \
|
|
PMIX_INFO_XFER(&info_tmp[_n + 1], &ch->info[_n]); \
|
|
} \
|
|
PMIX_INFO_FREE(ch->info, ch->nallocated); \
|
|
ch->nallocated = ninfo_tmp; \
|
|
ch->info = info_tmp; \
|
|
ch->ninfo = ninfo_tmp - 2; \
|
|
/* reset the timer */ \
|
|
if (ch->timer_active) { \
|
|
pmix_event_del(&ch->ev); \
|
|
} \
|
|
PMIX_POST_OBJECT(ch); \
|
|
ch->timer_active = true; \
|
|
pmix_event_add(&ch->ev, &pmix_globals.event_window); \
|
|
} \
|
|
} while (0)
|
|
|
|
END_C_DECLS
|
|
|
|
#endif /* PMIX_EVENT_H */
|