EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
em_chaining.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020, Nokia Solutions and Networks
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32 * @file
33 * EM event chaining support
34 */
35
36#ifndef EM_CHAINING_H_
37#define EM_CHAINING_H_
38
39#include <stdint.h>
40
41#include <event_machine.h>
42
43#include "em_chaining_types.h"
44#include "em_error.h"
45#include "em_event.h"
46#include "em_event_group.h"
48#include "em_event_types.h"
49#include "em_mem.h"
50#include "em_queue_inline.h"
51#include "em_queue_types.h"
52
53#ifdef __cplusplus
54extern "C" {
55#endif
56
57#pragma GCC visibility push(default)
58
59/**
60 * Send an event to out of EM.
61 * This function is declared as a weak symbol in default implementation
62 * in em_chaining.c, indicating that the user can override it during
63 * linking with another implementation if event chaining is used.
64 */
65em_status_t event_send_device(em_event_t event, em_queue_t queue);
66
67/**
68 * Send multiple events to out of EM.
69 * This function is declared as a weak symbol in default implementation
70 * in em_chaining.c, indicating that the user can override it during
71 * linking with another implementation if event chaining is used.
72 */
73int event_send_device_multi(const em_event_t events[], int num, em_queue_t queue);
74
75#pragma GCC visibility pop
76
77/**
78 * Initialize event chaining during start-up.
79 */
81
82/**
83 * Terminate event chaining during shut-down.
84 */
85em_status_t chaining_term(const event_chaining_t *event_chaining);
86
87/**
88 * Send an event to out of EM (e.g. to another device) via event-chaining and a
89 * user-provided function 'event_send_device()'.
90 * @see event_send_device()
91 */
92static inline em_status_t
93send_chaining(em_event_t event, em_queue_t chaining_queue)
94{
95 const unsigned int num_outq = em_shm->event_chaining.num_output_queues;
96 const em_sched_context_type_t sched_ctx_type =
98
99 if (num_outq == 0 || sched_ctx_type != EM_SCHED_CONTEXT_TYPE_ORDERED)
100 return event_send_device(event, chaining_queue);
101
102 /* always use the same output queue for each chaining queue */
103 const internal_queue_t iq = {.queue = chaining_queue};
104 em_queue_t output_queue;
105 queue_elem_t *output_q_elem;
106 uint32_t idx;
107
108 idx = ((uint32_t)iq.device_id + (uint32_t)iq.queue_id) % num_outq;
109 output_queue = em_shm->event_chaining.output_queues[idx];
110 output_q_elem = queue_elem_get(output_queue);
111
112 RETURN_ERROR_IF(EM_CHECK_LEVEL >= 3 && !output_q_elem,
113 EM_ERR_BAD_ID, EM_ESCOPE_EVENT_SEND_DEVICE,
114 "Invalid output queue:%" PRI_QUEUE "", output_queue);
115
116 return send_output(event, output_q_elem);
117}
118
119/**
120 * Send 'num' events out of EM (e.g. to another device) via event-chaining and a
121 * user-provided function 'event_send_device_multi()'.
122 * @see event_send_device_multi()
123 */
124static inline int
125send_chaining_multi(const em_event_t events[], const int num,
126 em_queue_t chaining_queue)
127{
128 const unsigned int num_outq = em_shm->event_chaining.num_output_queues;
129 const em_sched_context_type_t sched_ctx_type =
131
132 if (num_outq == 0 || sched_ctx_type != EM_SCHED_CONTEXT_TYPE_ORDERED)
133 return event_send_device_multi(events, num, chaining_queue);
134
135 /* always use the same output queue for each chaining queue */
136 const internal_queue_t iq = {.queue = chaining_queue};
137 em_queue_t output_queue;
138 queue_elem_t *output_q_elem;
139 uint32_t idx;
140
141 idx = ((uint32_t)iq.device_id + (uint32_t)iq.queue_id) % num_outq;
142 output_queue = em_shm->event_chaining.output_queues[idx];
143 output_q_elem = queue_elem_get(output_queue);
144
145 if (unlikely(EM_CHECK_LEVEL >= 3 && !output_q_elem)) {
146 INTERNAL_ERROR(EM_ERR_BAD_ID, EM_ESCOPE_EVENT_SEND_DEVICE_MULTI,
147 "Invalid output queue:%" PRI_QUEUE "", output_queue);
148 return 0;
149 }
150
151 return send_output_multi(events, num, output_q_elem);
152}
153
154/**
155 * Send an event tagged with an event group out of EM (e.g. to another device)
156 * via event-chaining and a user-provided function 'event_send_device()'.
157 * @see event_send_device()
158 */
159static inline em_status_t
160send_chaining_egrp(em_event_t event, event_hdr_t *const ev_hdr,
161 em_queue_t chaining_queue,
162 const event_group_elem_t *egrp_elem)
163{
164 if (!egrp_elem)
165 return send_chaining(event, chaining_queue);
166
167 event_group_elem_t *save_egrp_elem;
168 uint32_t save_egrp_gen;
169
170 /* Send to another DEVICE with an event group */
171 save_current_evgrp(&save_egrp_elem, &save_egrp_gen);
172 /*
173 * "Simulate" a dispatch round from evgrp perspective,
174 * send-device() instead of EO-receive()
175 */
176 event_group_set_local(ev_hdr->egrp, ev_hdr->egrp_gen, 1);
177
178 em_status_t stat = send_chaining(event, chaining_queue);
179 event_group_elem_t *const current_egrp_elem = em_locm.current.egrp_elem;
180
181 if (current_egrp_elem)
182 event_group_count_decrement(1, current_egrp_elem);
183 restore_current_evgrp(save_egrp_elem, save_egrp_gen);
184
185 return stat;
186}
187
188/**
189 * Send 'num' events tagged with an event group out of EM (e.g. to another device)
190 * via event-chaining and a user-provided function 'event_send_device_multi()'.
191 * @see event_send_device_multi()
192 */
193static inline int
194send_chaining_egrp_multi(const em_event_t events[], event_hdr_t *const ev_hdrs[],
195 const int num, em_queue_t chaining_queue,
196 const event_group_elem_t *egrp_elem)
197{
198 if (!egrp_elem)
199 return send_chaining_multi(events, num, chaining_queue);
200
201 event_group_elem_t *save_egrp_elem;
202 uint32_t save_egrp_gen;
203
204 /* Send to another DEVICE with an event group */
205 save_current_evgrp(&save_egrp_elem, &save_egrp_gen);
206 /*
207 * "Simulate" dispatch rounds from evgrp perspective,
208 * send-device() instead of EO-receive().
209 * Decrement evgrp-count by 'num' instead of by '1'.
210 * Note: event_group_set_local() called only once for
211 * all events.
212 */
213 event_group_set_local(ev_hdrs[0]->egrp, ev_hdrs[0]->egrp_gen, num);
214
215 int num_sent = send_chaining_multi(events, num, chaining_queue);
216 event_group_elem_t *const current_egrp_elem = em_locm.current.egrp_elem;
217
218 if (current_egrp_elem)
219 event_group_count_decrement(num, current_egrp_elem);
220 restore_current_evgrp(save_egrp_elem, save_egrp_gen);
221
222 return num_sent;
223}
224
225#ifdef __cplusplus
226}
227#endif
228
229#endif /* EM_CHAINING_H_ */
em_status_t chaining_init(event_chaining_t *event_chaining)
em_status_t event_send_device(em_event_t event, em_queue_t queue)
em_status_t chaining_term(const event_chaining_t *event_chaining)
int event_send_device_multi(const em_event_t events[], int num, em_queue_t queue)
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
#define EM_CHECK_LEVEL
#define PRI_QUEUE
uint32_t em_status_t
@ EM_ERR_BAD_ID
em_sched_context_type_t
@ EM_SCHED_CONTEXT_TYPE_ORDERED
em_sched_context_type_t sched_context_type
Definition em_mem.h:210
event_group_elem_t * egrp_elem
Definition em_mem.h:218
em_locm_current_t current
Definition em_mem.h:228
em_event_group_t egrp
uint32_t egrp_gen