EM-ODP  3.8.0-1
Event Machine on ODP
em_event.c
1 /*
2  * Copyright (c) 2015, 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 #include "em_include.h"
32 
33 /*
34  * Sanity check that no extra padding is added to the event_hdr_t by
35  * alignment directives etc.
36  */
37 typedef event_hdr_t _ev_hdr__size_check__arr_t[3];
38 COMPILE_TIME_ASSERT(sizeof(_ev_hdr__size_check__arr_t) ==
39  3 * sizeof(event_hdr_t), EVENT_HDR_SIZE_ERROR2);
40 
41 /*
42  * Verify the value set for EM_CHECK_LEVEL - this define is set either from
43  * the include/event_machine/platform/event_machine_config.h file or by the
44  * configure.ac option --enable-check-level=N.
45  */
46 COMPILE_TIME_ASSERT(EM_CHECK_LEVEL >= 0 && EM_CHECK_LEVEL <= 3,
47  EM_CHECK_LEVEL__BAD_VALUE);
48 
49 em_status_t event_init(void)
50 {
51  return EM_OK;
52 }
53 
54 void print_event_info(void)
55 {
56  EM_PRINT("\n"
57  "EM Events\n"
58  "---------\n"
59  "event-hdr size: %zu B\n",
60  sizeof(event_hdr_t));
61 
62  EM_DBG("\t\toffset\tsize\n"
63  "\t\t------\t----\n"
64  "esv.state_cnt:\t%3zu B\t%2zu B\n"
65  "esv.state:\t%3zu B\t%2zu B\n"
66  "flags:\t\t%3zu B\t%2zu B\n"
67  "align_offset:\t%3zu B\t%2zu B\n"
68  "event_type:\t%3zu B\t%2zu B\n"
69  "event:\t\t%3zu B\t%2zu B\n"
70  "event_size:\t%3zu B\t%2zu B\n"
71  "egrp_gen:\t%3zu B\t%2zu B\n"
72  "egrp:\t\t%3zu B\t%2zu B\n"
73  "tmo:\t\t%3zu B\t%2zu B\n"
74  "user_area info:\t%3zu B\t%2zu B\n"
75  "end_hdr_data:\t%3zu B\t%2zu B\n"
76  " <pad>\t\t%3zu B\n"
77  "end:\t\t%3zu B\t%2zu B\n",
78  offsetof(event_hdr_t, state_cnt), sizeof_field(event_hdr_t, state_cnt),
79  offsetof(event_hdr_t, state), sizeof_field(event_hdr_t, state),
80  offsetof(event_hdr_t, flags), sizeof_field(event_hdr_t, flags),
81  offsetof(event_hdr_t, align_offset), sizeof_field(event_hdr_t, align_offset),
82  offsetof(event_hdr_t, event_type), sizeof_field(event_hdr_t, event_type),
83  offsetof(event_hdr_t, event), sizeof_field(event_hdr_t, event),
84  offsetof(event_hdr_t, event_size), sizeof_field(event_hdr_t, event_size),
85  offsetof(event_hdr_t, egrp_gen), sizeof_field(event_hdr_t, egrp_gen),
86  offsetof(event_hdr_t, egrp), sizeof_field(event_hdr_t, egrp),
87  offsetof(event_hdr_t, tmo), sizeof_field(event_hdr_t, tmo),
88  offsetof(event_hdr_t, user_area), sizeof_field(event_hdr_t, user_area),
89  offsetof(event_hdr_t, end_hdr_data), sizeof_field(event_hdr_t, end_hdr_data),
90  offsetof(event_hdr_t, end) - offsetof(event_hdr_t, end_hdr_data),
91  offsetof(event_hdr_t, end), sizeof_field(event_hdr_t, end));
92 
93  EM_PRINT("\n");
94 }
95 
96 /**
97  * Helper for em_event_clone().
98  *
99  * Clone an event originating from an external odp pkt-pool.
100  * Initialize the new cloned event as an EM event and return it.
101  *
102  * Alloc and copy content via ODP.
103  * Also the ev_hdr in the odp-pkt user_area is copied.
104  */
105 em_event_t pkt_clone_odp(odp_packet_t pkt, odp_pool_t pkt_pool,
106  uint32_t offset, uint32_t size,
107  bool clone_uarea, bool is_clone_part)
108 {
109  odp_packet_t clone_pkt;
110 
111  if (is_clone_part) {
112  /* only data is copied, ODP-uarea isn't */
113  clone_pkt = odp_packet_copy_part(pkt, offset, size, pkt_pool);
114  if (unlikely(clone_pkt == ODP_PACKET_INVALID))
115  return EM_EVENT_UNDEF;
116 
117  const void *src_odp_uarea = odp_packet_user_area(pkt);
118  void *dst_odp_uarea = odp_packet_user_area(clone_pkt);
119  size_t cpy_size = sizeof(event_hdr_t);
120 
121  if (clone_uarea) {
122  /* copy ODP-uarea (EM-hdr + EM-uarea) */
123  uint32_t src_uarea_size = odp_packet_user_area_size(pkt);
124  uint32_t dst_uarea_size = odp_packet_user_area_size(clone_pkt);
125 
126  if (unlikely(dst_uarea_size < src_uarea_size)) {
127  odp_packet_free(clone_pkt);
128  return EM_EVENT_UNDEF;
129  }
130  /* update 'cpy_size' to include the whole ODP-uarea (EM-hdr + EM-uarea) */
131  cpy_size = src_uarea_size;
132  }
133  /* copy the EM-hdr and possibly also the EM-uarea if requested */
134  memcpy(dst_odp_uarea, src_odp_uarea, cpy_size);
135  } else {
136  /* identical clone, also ODP-uarea (EM-hdr + EM-uarea) is copied */
137  clone_pkt = odp_packet_copy(pkt, pkt_pool);
138  if (unlikely(clone_pkt == ODP_PACKET_INVALID))
139  return EM_EVENT_UNDEF;
140  }
141 
142  odp_packet_user_flag_set(clone_pkt, USER_FLAG_SET);
143 
144  odp_event_t odp_clone_event = odp_packet_to_event(clone_pkt);
145  event_hdr_t *clone_hdr = odp_packet_user_area(clone_pkt);
146  em_event_t clone_event = event_odp2em(odp_clone_event);
147 
148  /*
149  * Init hdr of event, also ESV init if needed.
150  * The clone_hdr is a copy of parent's, update only relevant fields.
151  */
152  if (esv_enabled())
153  clone_event = evstate_init(clone_event, clone_hdr, false);
154  else
155  clone_hdr->event = clone_event;
156 
157  clone_hdr->flags.all = 0;
158  clone_hdr->egrp = EM_EVENT_GROUP_UNDEF;
159  /* other fields: use parent's values as is */
160 
161  return clone_event;
162 }
163 
164 void
165 output_queue_track(queue_elem_t *const output_q_elem)
166 {
167  output_queue_track_t *const track =
169  const uint32_t qidx = output_q_elem->output.idx;
170 
171  if (track->used_queues[qidx] == NULL) {
172  track->used_queues[qidx] = output_q_elem;
173  track->idx[track->idx_cnt++] = qidx;
174  }
175 }
176 
177 void
178 output_queue_drain(const queue_elem_t *output_q_elem)
179 {
180  const em_queue_t output_queue = (em_queue_t)(uintptr_t)output_q_elem->queue;
181  const em_output_func_t output_fn =
182  output_q_elem->output.output_conf.output_fn;
183  void *const output_fn_args =
184  output_q_elem->output.output_conf.output_fn_args;
185 
186  const int deq_max = 32;
187 
188  em_event_t output_ev_tbl[deq_max];
189  /* use same event-tbl, dequeue odp events into the EM event-tbl */
190  odp_event_t *const odp_deq_events = (odp_event_t *)output_ev_tbl;
191 
192  const odp_queue_t odp_queue = output_q_elem->odp_queue;
193  unsigned int output_num;
194  int deq;
195  int ret;
196 
197  const bool esv_ena = esv_enabled();
198 
199  do {
200  deq = odp_queue_deq_multi(odp_queue,
201  odp_deq_events/*out=output_ev_tbl[]*/,
202  deq_max);
203  if (unlikely(deq <= 0))
204  return;
205 
206  output_num = (unsigned int)deq;
207  /* odp_deq_events[] == output_ev_tbl[] */
208  if (esv_ena) {
209  event_hdr_t *ev_hdrs[output_num];
210 
211  /* Restore hdls from ev_hdrs, odp-ev conv lost evgen */
212  event_to_hdr_multi(output_ev_tbl, ev_hdrs, output_num);
213  for (unsigned int i = 0; i < output_num; i++)
214  output_ev_tbl[i] = ev_hdrs[i]->event;
215  }
216 
217  ret = output_fn(output_ev_tbl, output_num,
218  output_queue, output_fn_args);
219 
220  if (unlikely((unsigned int)ret != output_num))
221  em_free_multi(&output_ev_tbl[ret], output_num - ret);
222  } while (deq > 0);
223 }
224 
225 void
226 output_queue_buffering_drain(void)
227 {
229 
230  for (unsigned int i = 0; i < track->idx_cnt; i++) {
231  int qidx = track->idx[i];
232  queue_elem_t *output_q_elem = track->used_queues[qidx];
233  env_spinlock_t *lock = &output_q_elem->output.lock;
234 
235  /*
236  * drain if lock available, otherwise another core is already
237  * draining so no need to do anything.
238  */
239  if (env_spinlock_trylock(lock)) {
240  output_queue_drain(output_q_elem);
241  env_spinlock_unlock(lock);
242  }
243 
244  track->idx[i] = 0;
245  track->used_queues[qidx] = NULL;
246  }
247  track->idx_cnt = 0;
248 }
249 
250 uint32_t event_vector_tbl(em_event_t vector_event,
251  em_event_t **event_tbl /*out*/)
252 {
253  odp_event_t odp_event = event_em2odp(vector_event);
254  odp_packet_vector_t pkt_vec = odp_packet_vector_from_event(odp_event);
255  odp_packet_t *pkt_tbl = NULL;
256  const int pkts = odp_packet_vector_tbl(pkt_vec, &pkt_tbl/*out*/);
257 
258  *event_tbl = (em_event_t *)pkt_tbl; /* Careful! Points to same table */
259 
260  if (!pkts)
261  return 0;
262 
263  event_hdr_t *ev_hdr_tbl[pkts];
264 
265  /*
266  * Init the event-table as needed, might contain EM events or
267  * ODP packets depending on source.
268  */
269  if (esv_enabled()) {
270  odp_packet_t odp_pkttbl[pkts];
271 
272  /*
273  * Drop ESV generation from event handles by converting to
274  * odp-packets, then init as needed as EM events.
275  */
276  events_em2pkt(*event_tbl/*in*/, odp_pkttbl/*out*/, pkts);
277 
278  event_init_pkt_multi(odp_pkttbl /*in*/, *event_tbl /*in,out*/,
279  ev_hdr_tbl /*out*/, pkts, false);
280  } else {
281  event_init_pkt_multi(pkt_tbl /*in*/, *event_tbl /*in,out*/,
282  ev_hdr_tbl /*out*/, pkts, false);
283  }
284 
285  return pkts;
286 }
287 
288 em_status_t event_vector_max_size(em_event_t vector_event, uint32_t *max_size /*out*/,
289  em_escope_t escope)
290 {
291  odp_event_t odp_event = event_em2odp(vector_event);
292  odp_packet_vector_t pktvec = odp_packet_vector_from_event(odp_event);
293  odp_pool_t odp_pool = odp_packet_vector_pool(pktvec);
294  pool_subpool_t pool_subpool = pool_subpool_odp2em(odp_pool);
295  em_pool_t pool = (em_pool_t)(uintptr_t)pool_subpool.pool;
296  int subpool = pool_subpool.subpool;
297 
298  if (unlikely(pool == EM_POOL_UNDEF)) {
299  /*
300  * Don't report an error if 'pool == EM_POOL_UNDEF' since that
301  * might happen if the vector is input from pktio that is using
302  * external (to EM) odp vector pools.
303  */
304  *max_size = 0;
305  return EM_OK; /* EM does not have the max_size info */
306  }
307 
308  const mpool_elem_t *pool_elem = pool_elem_get(pool);
309 
310  if (unlikely(!pool_elem ||
311  (EM_CHECK_LEVEL > 2 && !pool_allocated(pool_elem)))) {
312  *max_size = 0;
313  return INTERNAL_ERROR(EM_ERR_BAD_STATE, escope,
314  "Invalid pool:%" PRI_POOL "", pool);
315  }
316 
317  if (unlikely(subpool >= pool_elem->num_subpools)) {
318  /* not found */
319  *max_size = 0;
320  return INTERNAL_ERROR(EM_ERR_NOT_FOUND, escope,
321  "Subpool not found, pool:%" PRI_POOL "", pool);
322  }
323 
324  /* subpool index found, store corresponding size */
325  *max_size = pool_elem->size[subpool];
326 
327  return EM_OK;
328 }
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
em_event_t pkt_clone_odp(odp_packet_t pkt, odp_pool_t pkt_pool, uint32_t offset, uint32_t size, bool clone_uarea, bool is_clone_part)
Definition: em_event.c:105
em_event_t evstate_init(const em_event_t event, event_hdr_t *const ev_hdr, bool is_extev)
#define USER_FLAG_SET
struct event_hdr event_hdr_t
ENV_LOCAL em_locm_t em_locm
#define EM_CHECK_LEVEL
#define PRI_POOL
#define EM_POOL_UNDEF
@ EM_ERR_NOT_FOUND
@ EM_ERR_BAD_STATE
int(* em_output_func_t)(const em_event_t events[], const unsigned int num, const em_queue_t output_queue, void *output_fn_args)
#define EM_OK
uint32_t em_escope_t
#define EM_EVENT_UNDEF
#define EM_EVENT_GROUP_UNDEF
uint32_t em_status_t
void em_free_multi(em_event_t events[], int num)
output_queue_track_t output_queue_track
Definition: em_mem.h:242
union event_hdr::@34 flags
em_event_t event
em_event_group_t egrp
uint16_t size
Definition: em_pool_types.h:55
em_output_queue_conf_t output_conf
env_spinlock_t lock
odp_queue_t odp_queue
uint32_t queue