EM-ODP  3.7.0
Event Machine on ODP
em_error.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 /*
32  * EM Error Handling
33  */
34 
35 #include <libgen.h> /* basename() */
36 #include "em_include.h"
37 
38 /* Make sure that EM internally used error scopes are "seen" by EM_ESCOPE() */
39 COMPILE_TIME_ASSERT(EM_ESCOPE(EM_ESCOPE_API_MASK),
40  EM_ESCOPE_API_IS_NOT_PART_EM_ESCOPE__ERROR);
41 COMPILE_TIME_ASSERT(EM_ESCOPE(EM_ESCOPE_INTERNAL_MASK),
42  EM_ESCOPE_INTERNAL_IS_NOT_PART_OF_EM_ESCOPE__ERROR);
43 
44 static int error_handler_initialized; /* static always initialized to 0 */
45 
46 static early_log_t early_log = {default_log, vdefault_log};
47 
48 static em_status_t
49 early_error_handler(em_eo_t eo, em_status_t error, em_escope_t escope,
50  va_list args);
51 
52 static void
53 increment_global_err_cnt(void)
54 {
55  env_atomic64_inc(&em_shm->error_handler.global_error_count);
56 }
57 
58 uint64_t
59 load_global_err_cnt(void)
60 {
61  uint64_t cnt =
62  env_atomic64_get(&em_shm->error_handler.global_error_count);
63 
64  return cnt;
65 }
66 
67 ODP_PRINTF_FORMAT(2, 0)
68 int vdefault_log(em_log_level_t level, const char *fmt, va_list args)
69 {
70  int r;
71  FILE *logfd;
72 
73  switch (level) {
74  case EM_LOG_DBG:
75  case EM_LOG_PRINT:
76  logfd = stdout;
77  break;
78  default:
79  /* also level=EM_LOG_ERR */
80  logfd = stderr;
81  break;
82  }
83 
84  r = vfprintf(logfd, fmt, args);
85  return r;
86 }
87 
88 ODP_PRINTF_FORMAT(2, 3)
89 int default_log(em_log_level_t level, const char *fmt, ...)
90 {
91  va_list args;
92  int r;
93 
94  va_start(args, fmt);
95  r = vdefault_log(level, fmt, args);
96  va_end(args);
97 
98  return r;
99 }
100 
101 /**
102  * Early EM Error Handler
103  *
104  * The early error handler is used when reporting errors at startup before
105  * the default, application and EO specific error handlers have been set up.
106  *
107  * @param eo unused
108  * @param error The error code (reason), see em_status_e
109  * @param escope The error scope from within the error was reported, also
110  * tells whether the error was EM internal or application
111  * specific
112  * @param args va_list of args
113  *
114  * @return The function may not return depending on implementation / error
115  * code / error scope. If it returns, the return value is the original
116  * (or modified) error code from the caller.
117  */
118 static em_status_t
119 early_error_handler(em_eo_t eo, em_status_t error, em_escope_t escope,
120  va_list args)
121 {
122  int core_id = odp_cpu_id(); /* em_core_id() does not work here */
123  em_log_func_t log_fn = early_log.log_fn;
124  em_vlog_func_t vlog_fn = early_log.vlog_fn;
125 
126  if (EM_ESCOPE(escope)) {
127  /*
128  * va_list contains: __FILE__, __func__, __LINE__, (format),
129  * ## __VA_ARGS__ as reported by the INTERNAL_ERROR macro
130  */
131  char *file = va_arg(args, char*);
132  const char *func = va_arg(args, const char*);
133  const int line = va_arg(args, const int);
134  const char *format = va_arg(args, const char*);
135  const char *base = basename(file);
136  (void)eo;
137 
138  log_fn(EM_LOG_ERR, "\n"
139  "EM ERROR:0x%08X ESCOPE:0x%08X (Early Error)\n"
140  "core:%02i %s:%i %s()\n",
141  error, escope, core_id, base, line, func);
142  vlog_fn(EM_LOG_ERR, format, args);
143  log_fn(EM_LOG_ERR, "\n");
144  } else {
145  /* va_list from application - don't touch. */
146  log_fn(EM_LOG_ERR, "\n"
147  "APPL ERROR:0x%08X ESCOPE:0x%08X (Early Error)\n"
148  "core:%02i\n",
149  error, escope, core_id);
150  }
151 
152  if (unlikely(EM_ERROR_IS_FATAL(error))) {
153  log_fn(EM_LOG_ERR,
154  "FATAL EM ERROR:0x%08X (Early Error) - ABORT!\n",
155  error);
156  abort();
157  }
158 
159  return error;
160 }
161 
162 /**
163  * Default EM Error Handler
164  *
165  * The default error handler is called upon error if the application(s)
166  * have not registered their own global and/or EO-specific error handlers
167  *
168  * @param eo EO reporting the error (if applicable)
169  * @param error The error code (reason), see em_status_e
170  * @param escope The error scope from within the error was reported, also
171  * tells whether the error was EM internal or application
172  * specific
173  * @param args va_list of args
174  *
175  * @return The function may not return depending on implementation / error
176  * code / error scope. If it returns, the return value is the original
177  * (or modified) error code from the caller.
178  */
181  va_list args)
182 {
183  char eo_str[sizeof("EO:xxxxxx-abdc ") + EM_EO_NAME_LEN];
184  const int core_id = em_core_id();
185  const uint64_t local_err_cnt = em_locm.error_count;
186  const uint64_t global_err_cnt = load_global_err_cnt();
187 
188  if (eo == EM_EO_UNDEF) {
189  eo_str[0] = '\0';
190  } else {
191  char eo_name[EM_EO_NAME_LEN];
192  size_t nlen;
193 
194  nlen = em_eo_get_name(eo, eo_name, sizeof(eo_name));
195  eo_name[nlen] = '\0';
196 
197  snprintf(eo_str, sizeof(eo_str),
198  "EO:%" PRI_EO "-\"%s\" ", eo, eo_name);
199  eo_str[sizeof(eo_str) - 1] = '\0';
200  }
201 
202  if (EM_ESCOPE(escope)) {
203  /*
204  * va_list contains: __FILE__, __func__, __LINE__, (format),
205  * ## __VA_ARGS__ as reported by the INTERNAL_ERROR macro
206  */
207  char *file = va_arg(args, char*);
208  const char *func = va_arg(args, const char*);
209  const int line = va_arg(args, const int);
210  const char *format = va_arg(args, const char*);
211  const char *base = basename(file);
212 
213  EM_LOG(EM_LOG_ERR, "\n"
214  "EM ERROR:0x%08X ESCOPE:0x%08X %s\n"
215  "core:%02i ecount:%" PRIu64 "(%" PRIu64 ") %s:%i %s()\n",
216  error, escope, eo_str, core_id,
217  global_err_cnt, local_err_cnt,
218  base, line, func);
219  EM_VLOG(EM_LOG_ERR, format, args);
220  EM_LOG(EM_LOG_ERR, "\n");
221  } else {
222  /* va_list from application - don't touch. */
223  EM_LOG(EM_LOG_ERR, "\n"
224  "APPL ERROR:0x%08X ESCOPE:0x%08X %s\n"
225  "core:%02i ecount:%" PRIu64 "(%" PRIu64 ")\n",
226  error, escope, eo_str, core_id,
227  global_err_cnt, local_err_cnt);
228  }
229 
230  if (unlikely(EM_ERROR_IS_FATAL(error))) {
231  EM_LOG(EM_LOG_ERR, "FATAL EM ERROR:0x%08X - ABORT!\n", error);
232  abort();
233  }
234 
235  return error;
236 }
237 
238 /**
239  * Select and call an error handler.
240  *
241  * @param error Error code
242  * @param escope Error scope. Identifies the scope for interpreting
243  * the error code and variable arguments.
244  * @param args_list Variable number and type of arguments
245  *
246  * @return Returns the 'error' argument given as input if the called error
247  * handler has not changed this value.
248  */
250 select_error_handler(em_status_t error, em_escope_t escope, va_list args_list)
251 {
252  if (unlikely(!error_handler_initialized)) {
253  /*
254  * Early errors reported at startup before error handling
255  * is properly initialized.
256  */
257  error = early_error_handler(EM_EO_UNDEF, error, escope,
258  args_list);
259  return error;
260  }
261 
262  em_error_handler_t error_handler;
263  em_error_handler_t eo_handler;
264  em_log_func_t log_fn = em_shm->log_fn;
265  const eo_elem_t *const eo_elem = eo_elem_current();
266  em_eo_t eo = EM_EO_UNDEF;
267 
268  /* Global error handler, default or user registered */
269  error_handler = em_shm->error_handler.em_error_handler;
270 
271  if (eo_elem && eo_allocated(eo_elem)) {
272  eo_handler = eo_elem->error_handler_func;
273  eo = eo_elem->eo;
274  if (eo_handler)
275  error_handler = eo_handler;
276  }
277 
278  /* fallback, should never happen */
279  if (unlikely(error_handler == NULL)) {
280  error_handler = early_error_handler;
281  log_fn = early_log.log_fn; /* for the "FATAL EM ERROR:" below */
282  }
283 
284  /*
285  * Call the selected error handler and possibly change the error code.
286  */
287  error = error_handler(eo, error, escope, args_list);
288 
289  if (error != EM_OK) {
290  /* Increase the error count, used in logs/printouts */
291  increment_global_err_cnt();
292  em_locm.error_count += 1;
293  }
294 
295  /*
296  * An error handler cannot return a fatal EM-error and continue running.
297  */
298  if (unlikely(EM_ESCOPE(escope) && EM_ERROR_IS_FATAL(error))) {
299  log_fn(EM_LOG_ERR,
300  "FATAL EM ERROR:0x%08X ESCOPE:0x%08X - ABORT!\n"
301  "EM: an error-handler must not return a fatal EM-error!",
302  error, escope);
303  abort();
304  }
305 
306  /* Return input error or value changed by error_handler */
307  return error;
308 }
309 
310 /**
311  * Called ONLY from INTERNAL_ERROR macro - do not use for anything else!
312  * internal_error((error), (escope), __FILE__, __func__, __LINE__,
313  * (format), ## __VA_ARGS__)
314  */
317 {
318  /*
319  * va_list contains:
320  * __FILE__, __func__, __LINE__, (format), ## __VA_ARGS__
321  */
322  va_list args;
323 
324  va_start(args, escope);
325 
326  /* Select and call an error handler. Possibly modifies the error code*/
327  error = select_error_handler(error, escope, args);
328 
329  va_end(args);
330 
331  /* Return input error or value changed by error_handler */
332  return error;
333 }
334 
335 /**
336  * Initialize the EM Error Handling
337  */
338 void
340 {
341  env_spinlock_init(&em_shm->error_handler.lock);
342 
343  em_shm->error_handler.em_error_handler = default_error_handler;
344 
345  env_atomic64_init(&em_shm->error_handler.global_error_count);
346 
347  em_shm->error_handler.initialized = 1; /* For API functions */
348  error_handler_initialized = 1; /* For early error handler select */
349 }
350 
352 early_log_init(em_log_func_t user_log_fn, em_vlog_func_t user_vlog_fn)
353 {
354  /* Check that both log fns are either set or both NULL */
355  int is_log_null = user_log_fn == NULL;
356  int is_vlog_null = user_vlog_fn == NULL;
357 
358  if (is_log_null != is_vlog_null)
359  return EM_ERR_BAD_POINTER;
360 
361  /* store user provided log functions */
362  if (user_log_fn != NULL) {
363  early_log.log_fn = user_log_fn;
364  early_log.vlog_fn = user_vlog_fn;
365  }
366 
367  return EM_OK;
368 }
369 
370 void
371 log_init(void)
372 {
373  em_shm->log_fn = early_log.log_fn;
374  em_shm->vlog_fn = early_log.vlog_fn;
375 }
EM_OK
#define EM_OK
Definition: event_machine_types.h:329
EM_ERROR_IS_FATAL
#define EM_ERROR_IS_FATAL(error)
Definition: event_machine_hw_types.h:423
eo_elem_t::eo
em_eo_t eo
Definition: em_eo_types.h:81
em_eo_get_name
size_t em_eo_get_name(em_eo_t eo, char *name, size_t maxlen)
Definition: event_machine_eo.c:236
error_init
void error_init(void)
Definition: em_error.c:339
em_log_func_t
int(* em_log_func_t)(em_log_level_t level, const char *fmt,...) __attribute__((format(printf
Definition: event_machine_hw_types.h:329
em_shm_t::log_fn
em_log_func_t log_fn
Definition: em_mem.h:57
em_locm
ENV_LOCAL em_locm_t em_locm
PRI_EO
#define PRI_EO
Definition: event_machine_types.h:97
EM_EO_UNDEF
#define EM_EO_UNDEF
Definition: event_machine_types.h:95
early_log_t
Definition: em_error_types.h:40
internal_error
em_status_t internal_error(em_status_t error, em_escope_t escope,...)
Definition: em_error.c:316
eo_elem_t::error_handler_func
em_error_handler_t error_handler_func
Definition: em_eo_types.h:69
eo_elem_t
Definition: em_eo_types.h:47
select_error_handler
em_status_t select_error_handler(em_status_t error, em_escope_t escope, va_list args_list)
Definition: em_error.c:250
EM_ESCOPE
#define EM_ESCOPE(escope)
Definition: event_machine_types.h:365
EM_EO_NAME_LEN
#define EM_EO_NAME_LEN
Definition: event_machine_config.h:155
em_escope_t
uint32_t em_escope_t
Definition: event_machine_types.h:348
em_status_t
uint32_t em_status_t
Definition: event_machine_types.h:321
em_error_handler_t
em_status_t(* em_error_handler_t)(em_eo_t eo, em_status_t error, em_escope_t escope, va_list args)
Definition: event_machine_error.h:94
em_shm
em_shm_t * em_shm
Definition: event_machine_init.c:41
em_include.h
em_log_level_t
em_log_level_t
Definition: event_machine_hw_types.h:318
em_core_id
int em_core_id(void)
Definition: event_machine_core.c:34
EM_ESCOPE_API_MASK
#define EM_ESCOPE_API_MASK
Definition: event_machine_types.h:383
EM_ERR_BAD_POINTER
@ EM_ERR_BAD_POINTER
Definition: event_machine_hw_types.h:271
em_vlog_func_t
int(*) typedef int(* em_vlog_func_t)(em_log_level_t level, const char *fmt, va_list args)
Definition: event_machine_hw_types.h:337
default_error_handler
em_status_t default_error_handler(em_eo_t eo, em_status_t error, em_escope_t escope, va_list args)
Definition: em_error.c:180
em_shm_t::vlog_fn
em_vlog_func_t vlog_fn
Definition: em_mem.h:59
EM_ESCOPE_INTERNAL_MASK
#define EM_ESCOPE_INTERNAL_MASK
Definition: event_machine_hw_types.h:445
em_locm_t::error_count
uint64_t error_count
Definition: em_mem.h:227