EM-ODP  3.8.0-1
Event Machine on ODP
em_chaining.c
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 #include "em_include.h"
32 
33 /* em_output_func_t for event-chaining output*/
34 int chaining_output(const em_event_t events[], const unsigned int num,
35  const em_queue_t output_queue, void *output_fn_args);
36 
37 /**
38  * Default implementation is declared as a weak symbol, meaning that the
39  * user can override the function during linking with another implementation.
40  */
41 __attribute__((weak))
42 em_status_t event_send_device(em_event_t event, em_queue_t queue)
43 {
44  internal_queue_t iq = {.queue = queue};
45 
46  (void)event;
47 
50  "No %s() function given!\t"
51  "device:0x%" PRIx16 " Q-id:0x%" PRIx16 "\n",
52  __func__, iq.device_id, iq.queue_id);
53 }
54 
55 /**
56  * Default implementation is declared as a weak symbol, meaning that the
57  * user can override the function during linking with another implementation.
58  */
59 __attribute__((weak))
60 int event_send_device_multi(const em_event_t events[], int num, em_queue_t queue)
61 {
62  internal_queue_t iq = {.queue = queue};
63 
64  (void)events;
65  (void)num;
66 
69  "No %s() function given!\t"
70  "device:0x%" PRIx16 " Q-id:0x%" PRIx16 "\n",
71  __func__, iq.device_id, iq.queue_id);
72  return 0;
73 }
74 
75 static int
76 read_config_file(void)
77 {
78  const char *conf_str;
79  int val = 0;
80  bool val_bool = false;
81  int ret;
82 
83  /* Zero all options first */
84  memset(&em_shm->opt.event_chaining, 0, sizeof(em_shm->opt.event_chaining));
85 
86  EM_PRINT("EM Event-Chaining config:\n");
87  /*
88  * Option: event_chaining.order_keep - runtime enable/disable
89  */
90  conf_str = "event_chaining.order_keep";
91  ret = em_libconfig_lookup_bool(&em_shm->libconfig, conf_str, &val_bool);
92  if (unlikely(!ret)) {
93  EM_LOG(EM_LOG_ERR, "Config option '%s' not found\n", conf_str);
94  return -1;
95  }
96  /* store & print the value */
97  em_shm->opt.event_chaining.order_keep = val_bool;
98  EM_PRINT(" %s: %s(%d)\n", conf_str, val_bool ? "true" : "false",
99  val_bool);
100 
101  /* Read no more options if ordering is disabled */
102  if (!em_shm->opt.event_chaining.order_keep)
103  return 0; /* Note! */
104 
105  /* Temporary: Event chaining re-ordering not yet supported */
106  if (unlikely(em_shm->opt.event_chaining.order_keep)) {
107  EM_LOG(EM_LOG_ERR,
108  "Config option %s: %s(%d) currently not supported\n",
109  conf_str, val_bool ? "true" : "false", val_bool);
110  return -1;
111  }
112 
113  /*
114  * Option: event_chaining.num_order_queues
115  * (only read if .order_keep == true above)
116  */
117  conf_str = "event_chaining.num_order_queues";
118  ret = em_libconfig_lookup_int(&em_shm->libconfig, conf_str, &val);
119  if (unlikely(!ret)) {
120  EM_LOG(EM_LOG_ERR, "Config option '%s' not found.\n", conf_str);
121  return -1;
122  }
123  if (val < 0 || val > MAX_CHAINING_OUTPUT_QUEUES) {
124  EM_LOG(EM_LOG_ERR, "Bad config value '%s = %d' (max: %d)\n",
125  conf_str, val, MAX_CHAINING_OUTPUT_QUEUES);
126  return -1;
127  }
128  /* store & print the value */
129  em_shm->opt.event_chaining.num_order_queues = val;
130  EM_PRINT(" %s: %d (max: %d)\n", conf_str, val,
131  MAX_CHAINING_OUTPUT_QUEUES);
132 
133  return 0;
134 }
135 
138 {
139  if (read_config_file())
140  return EM_ERR_LIB_FAILED;
141 
142  /* Remains '0' if 'event_chaining.order_keep = false' in config file */
143  event_chaining->num_output_queues = 0;
144 
145  for (unsigned int i = 0; i < MAX_CHAINING_OUTPUT_QUEUES; i++)
146  event_chaining->output_queues[i] = EM_QUEUE_UNDEF;
147 
148  if (!em_shm->opt.event_chaining.order_keep)
149  return EM_OK; /* don't create output queues for event chaining */
150 
151  /*
152  * Create EM output queues for event chaining, needed to maintain event
153  * order during an ordered context
154  */
155  em_queue_conf_t queue_conf;
156  em_output_queue_conf_t output_conf;
157 
158  memset(&queue_conf, 0, sizeof(queue_conf));
159  memset(&output_conf, 0, sizeof(output_conf));
160 
161  queue_conf.flags = EM_QUEUE_FLAG_DEFAULT;
162  queue_conf.min_events = 0; /* system default */
163  queue_conf.conf_len = sizeof(output_conf);
164  queue_conf.conf = &output_conf;
165  /* Set output-queue callback function, no args needed */
166  output_conf.output_fn = chaining_output;
167  output_conf.output_fn_args = NULL;
168  output_conf.args_len = 0;
169 
170  const unsigned int num = em_shm->opt.event_chaining.num_order_queues;
171  unsigned char idx = 0;
172 
173  for (unsigned int i = 0; i < num; i++) {
174  char name[EM_QUEUE_NAME_LEN];
175 
176  snprintf(name, sizeof(name), "Event-Chaining-Output-%02u", idx);
177  idx++;
178  name[sizeof(name) - 1] = '\0';
179 
180  em_queue_t output_queue = em_queue_create(name,
184  &queue_conf);
185  if (unlikely(output_queue == EM_QUEUE_UNDEF))
186  return EM_ERR_ALLOC_FAILED;
187 
188  event_chaining->num_output_queues++;
189  event_chaining->output_queues[i] = output_queue;
190  }
191 
192  return EM_OK;
193 }
194 
196 chaining_term(const event_chaining_t *event_chaining)
197 {
198  /* num = 0 if 'event_chaining.order_keep = false' in config file */
199  const unsigned int num = event_chaining->num_output_queues;
200 
201  for (unsigned int i = 0; i < num; i++) {
202  em_queue_t output_queue = event_chaining->output_queues[i];
203  /* delete the output queues associated with event chaining */
204  em_status_t stat = em_queue_delete(output_queue);
205 
206  if (unlikely(stat != EM_OK))
207  return stat;
208  }
209 
210  return EM_OK;
211 }
212 
213 /**
214  * Output-queue callback function of type 'em_output_func_t' for Event-Chaining.
215  * Only needed when sending during an ordered-context when the EM config file
216  * option is set to 'event_chaining.order_keep = true'.
217  */
218 int
219 chaining_output(const em_event_t events[], const unsigned int num,
220  const em_queue_t output_queue, void *output_fn_args)
221 {
222  /*
223  * NOTE!
224  * Temporary: Not supporting the EM config file option
225  * 'event_chaining.order_keep = true' at the moment, checked during
226  * chaining_init() -> read_config_file().
227  * This function will thus not be called until support added.
228  */
229  em_queue_t chaining_queue = EM_QUEUE_UNDEF;
230 
231  (void)output_queue;
232  (void)output_fn_args;
233 
234  if (unlikely(num <= 0))
235  return 0;
236 
237  if (num == 1) {
238  em_status_t stat = event_send_device(events[0], chaining_queue);
239 
240  if (unlikely(stat != EM_OK))
241  return 0;
242  return 1;
243  }
244 
245  /*
246  * num > 1:
247  */
248  int ret = event_send_device_multi(events, num, chaining_queue);
249 
250  if (unlikely((unsigned int)ret != num)) {
251  if (ret < 0)
252  return 0;
253  else
254  return ret;
255  }
256 
257  return num;
258 }
em_status_t chaining_init(event_chaining_t *event_chaining)
Definition: em_chaining.c:137
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)
Definition: em_chaining.c:196
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:43
em_shm_t * em_shm
#define EM_QUEUE_NAME_LEN
#define EM_ESCOPE_EVENT_SEND_DEVICE
@ EM_QUEUE_TYPE_OUTPUT
#define EM_QUEUE_PRIO_UNDEF
@ EM_ERR_ALLOC_FAILED
@ EM_ERR_NOT_IMPLEMENTED
@ EM_ERR_LIB_FAILED
#define EM_QUEUE_FLAG_DEFAULT
#define EM_ESCOPE_EVENT_SEND_DEVICE_MULTI
#define EM_OK
#define EM_QUEUE_GROUP_UNDEF
uint32_t em_status_t
#define EM_QUEUE_UNDEF
em_status_t em_queue_delete(em_queue_t queue)
em_queue_t em_queue_create(const char *name, em_queue_type_t type, em_queue_prio_t prio, em_queue_group_t group, const em_queue_conf_t *conf)
em_queue_flag_t flags
unsigned int min_events
libconfig_t libconfig
Definition: em_mem.h:146