1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4 * University Research and Technology
5 * Corporation. All rights reserved.
6 * Copyright (c) 2004-2006 The University of Tennessee and The University
7 * of Tennessee Research Foundation. All rights
8 * reserved.
9 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10 * University of Stuttgart. All rights reserved.
11 * Copyright (c) 2004-2005 The Regents of the University of California.
12 * All rights reserved.
13 * Copyright (c) 2015-2018 Intel, Inc. All rights reserved.
14 * $COPYRIGHT$
15 *
16 * Additional copyrights may follow
17 *
18 * $HEADER$
19 */
20
21 #ifndef PMIX_EVENT_H
22 #define PMIX_EVENT_H
23
24 #include <src/include/pmix_config.h>
25 #include "src/include/types.h"
26 #include PMIX_EVENT_HEADER
27
28 #include <pmix_common.h>
29 #include "src/class/pmix_list.h"
30 #include "src/util/output.h"
31
32 BEGIN_C_DECLS
33
34 #define PMIX_EVENT_ORDER_NONE 0x00
35 #define PMIX_EVENT_ORDER_FIRST 0x01
36 #define PMIX_EVENT_ORDER_LAST 0x02
37 #define PMIX_EVENT_ORDER_BEFORE 0x04
38 #define PMIX_EVENT_ORDER_AFTER 0x08
39 #define PMIX_EVENT_ORDER_PREPEND 0x10
40 #define PMIX_EVENT_ORDER_APPEND 0x20
41
42 /* define an internal attribute for marking that the
43 * server processed an event before passing it up
44 * to its host in case it comes back down - avoids
45 * infinite loop */
46 #define PMIX_SERVER_INTERNAL_NOTIFY "pmix.srvr.internal.notify"
47
48
49 /* define a struct for tracking registration ranges */
50 typedef struct {
51 pmix_data_range_t range;
52 pmix_proc_t *procs;
53 size_t nprocs;
54 } pmix_range_trkr_t;
55
56 /* define a common struct for tracking event handlers */
57 typedef struct {
58 pmix_list_item_t super;
59 char *name;
60 size_t index;
61 uint8_t precedence;
62 char *locator;
63 pmix_proc_t source; // who generated this event
64 /* When registering for events, callers can specify
65 * the range of sources from which they are willing
66 * to receive notifications - e.g., for callers to
67 * define different handlers for events coming from
68 * the RM vs those coming from their peers. We use
69 * the rng field to track these values upon registration.
70 */
71 pmix_range_trkr_t rng;
72 /* For registration, we use the affected field to track
73 * the range of procs that, if affected by the event,
74 * should cause the handler to be called (subject, of
75 * course, to any rng constraints).
76 */
77 pmix_proc_t *affected;
78 size_t naffected;
79 pmix_notification_fn_t evhdlr;
80 void *cbobject;
81 pmix_status_t *codes;
82 size_t ncodes;
83 } pmix_event_hdlr_t;
84 PMIX_CLASS_DECLARATION(pmix_event_hdlr_t);
85
86 /* define an object for tracking status codes we are actively
87 * registered to receive */
88 typedef struct {
89 pmix_list_item_t super;
90 pmix_status_t code;
91 size_t nregs;
92 } pmix_active_code_t;
93 PMIX_CLASS_DECLARATION(pmix_active_code_t);
94
95 /* define an object for housing the different lists of events
96 * we have registered so we can easily scan them in precedent
97 * order when we get an event */
98 typedef struct {
99 pmix_object_t super;
100 size_t nhdlrs;
101 pmix_event_hdlr_t *first;
102 pmix_event_hdlr_t *last;
103 pmix_list_t actives;
104 pmix_list_t single_events;
105 pmix_list_t multi_events;
106 pmix_list_t default_events;
107 } pmix_events_t;
108 PMIX_CLASS_DECLARATION(pmix_events_t);
109
110 /* define an object for chaining event notifications thru
111 * the local state machine. Each registered event handler
112 * that asked to be notified for a given code is given a
113 * chance to "see" the reported event, starting with
114 * single-code handlers, then multi-code handlers, and
115 * finally default handlers. This object provides a
116 * means for us to relay the event across that chain
117 */
118 typedef struct pmix_event_chain_t {
119 pmix_list_item_t super;
120 pmix_status_t status;
121 pmix_event_t ev;
122 bool timer_active;
123 bool nondefault;
124 bool endchain;
125 pmix_proc_t source;
126 pmix_data_range_t range;
127 /* When generating events, callers can specify
128 * the range of targets to receive notifications.
129 */
130 pmix_proc_t *targets;
131 size_t ntargets;
132 /* the processes that we affected by the event */
133 pmix_proc_t *affected;
134 size_t naffected;
135 /* any info provided by the event generator */
136 pmix_info_t *info;
137 size_t ninfo;
138 size_t nallocated;
139 pmix_info_t *results;
140 size_t nresults;
141 pmix_event_hdlr_t *evhdlr;
142 pmix_op_cbfunc_t final_cbfunc;
143 void *final_cbdata;
144 } pmix_event_chain_t;
145 PMIX_CLASS_DECLARATION(pmix_event_chain_t);
146
147 /* prepare a chain for processing by cycling across provided
148 * info structs and translating those supported by the event
149 * system into the chain object*/
150 pmix_status_t pmix_prep_event_chain(pmix_event_chain_t *chain,
151 const pmix_info_t *info, size_t ninfo,
152 bool xfer);
153
154 /* invoke the error handler that is registered against the given
155 * status, passing it the provided info on the procs that were
156 * affected, plus any additional info provided by the server */
157 void pmix_invoke_local_event_hdlr(pmix_event_chain_t *chain);
158
159 bool pmix_notify_check_range(pmix_range_trkr_t *rng,
160 const pmix_proc_t *proc);
161
162 bool pmix_notify_check_affected(pmix_proc_t *interested, size_t ninterested,
163 pmix_proc_t *affected, size_t naffected);
164
165
166 /* invoke the server event notification handler */
167 pmix_status_t pmix_server_notify_client_of_event(pmix_status_t status,
168 const pmix_proc_t *source,
169 pmix_data_range_t range,
170 const pmix_info_t info[], size_t ninfo,
171 pmix_op_cbfunc_t cbfunc, void *cbdata);
172
173 void pmix_event_timeout_cb(int fd, short flags, void *arg);
174
175 #define PMIX_REPORT_EVENT(e, p, r, f) \
176 do { \
177 pmix_event_chain_t *ch, *cp; \
178 size_t n, ninfo; \
179 pmix_info_t *info; \
180 pmix_proc_t proc; \
181 \
182 ch = NULL; \
183 /* see if we already have this event cached */ \
184 PMIX_LIST_FOREACH(cp, &pmix_globals.cached_events, pmix_event_chain_t) { \
185 if (cp->status == (e)) { \
186 ch = cp; \
187 break; \
188 } \
189 } \
190 if (NULL == ch) { \
191 /* nope - need to add it */ \
192 ch = PMIX_NEW(pmix_event_chain_t); \
193 ch->status = (e); \
194 ch->range = (r); \
195 PMIX_LOAD_PROCID(&ch->source, (p)->nptr->nspace, \
196 (p)->info->pname.rank); \
197 PMIX_PROC_CREATE(ch->affected, 1); \
198 ch->naffected = 1; \
199 PMIX_LOAD_PROCID(ch->affected, (p)->nptr->nspace, \
200 (p)->info->pname.rank); \
201 /* if I'm a client or tool and this is my server, then we don't */ \
202 /* set the targets - otherwise, we do */ \
203 if (!PMIX_PROC_IS_SERVER(pmix_globals.mypeer) && \
204 !PMIX_CHECK_PROCID(&pmix_client_globals.myserver->info->pname, \
205 &(p)->info->pname)) { \
206 PMIX_PROC_CREATE(ch->targets, 1); \
207 ch->ntargets = 1; \
208 PMIX_LOAD_PROCID(ch->targets, (p)->nptr->nspace, PMIX_RANK_WILDCARD); \
209 } \
210 /* if this is lost-connection-to-server, then we let it go to */ \
211 /* the default event handler - otherwise, we don't */ \
212 if (PMIX_ERR_LOST_CONNECTION_TO_SERVER != (e) && \
213 PMIX_ERR_UNREACH != (e)) { \
214 ch->ninfo = 1; \
215 ch->nallocated = 3; \
216 PMIX_INFO_CREATE(ch->info, ch->nallocated); \
217 /* mark for non-default handlers only */ \
218 PMIX_INFO_LOAD(&ch->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); \
219 } else { \
220 ch->nallocated = 2; \
221 PMIX_INFO_CREATE(ch->info, ch->nallocated); \
222 } \
223 ch->final_cbfunc = (f); \
224 ch->final_cbdata = ch; \
225 /* cache it */ \
226 pmix_list_append(&pmix_globals.cached_events, &ch->super); \
227 ch->timer_active = true; \
228 pmix_event_assign(&ch->ev, pmix_globals.evbase, -1, 0, \
229 pmix_event_timeout_cb, ch); \
230 PMIX_POST_OBJECT(ch); \
231 pmix_event_add(&ch->ev, &pmix_globals.event_window); \
232 } else { \
233 /* add this peer to the array of sources */ \
234 pmix_strncpy(proc.nspace, (p)->nptr->nspace, PMIX_MAX_NSLEN); \
235 proc.rank = (p)->info->pname.rank; \
236 ninfo = ch->nallocated + 1; \
237 PMIX_INFO_CREATE(info, ninfo); \
238 /* must keep the hdlr name and return object at the end, so prepend */ \
239 PMIX_INFO_LOAD(&info[0], PMIX_PROCID, \
240 &proc, PMIX_PROC); \
241 for (n=0; n < ch->ninfo; n++) { \
242 PMIX_INFO_XFER(&info[n+1], &ch->info[n]); \
243 } \
244 PMIX_INFO_FREE(ch->info, ch->nallocated); \
245 ch->nallocated = ninfo; \
246 ch->info = info; \
247 ch->ninfo = ninfo - 2; \
248 /* reset the timer */ \
249 pmix_event_del(&ch->ev); \
250 PMIX_POST_OBJECT(ch); \
251 pmix_event_add(&ch->ev, &pmix_globals.event_window); \
252 } \
253 } while(0)
254
255
256 END_C_DECLS
257
258 #endif /* PMIX_EVENT_H */