eolian: initial API for a new panic mechanism
authorDaniel Kolesa <d.kolesa@osg.samsung.com>
Fri, 16 Mar 2018 14:41:24 +0000 (15:41 +0100)
committerWonki Kim <wonki_.kim@samsung.com>
Tue, 10 Apr 2018 11:21:58 +0000 (20:21 +0900)
This will be used to handle unrecoverable errors.
For robustness, you will be able to set a custom
panic callback, jump and try to recover manually.

src/lib/eolian/Eolian.h
src/lib/eolian/eolian_database.c
src/lib/eolian/eolian_database.h

index 370c334..54300cf 100644 (file)
@@ -200,6 +200,8 @@ typedef struct _Eolian_Unit Eolian_Unit;
 #define EOLIAN_OBJECT(expr) EOLIAN_CAST(Eolian_Object, expr)
 #define EOLIAN_UNIT(expr) EOLIAN_CAST(Eolian_Unit, expr)
 
+typedef void (*Eolian_Panic_Cb)(const Eolian_State *state, Eina_Stringshare *msg);
+
 typedef enum
 {
    EOLIAN_OBJECT_UNKNOWN = 0,
@@ -487,6 +489,11 @@ EAPI int eolian_shutdown(void);
  *
  * You need to free this with eolian_free once you're done.
  *
+ * This will assign a default panic function, which printers the error
+ * message passed to it into the standard Eolian log.
+ *
+ * @see eolian_panic_cb_set
+ *
  * @return A new state (or NULL on failure).
  *
  * @ingroup Eolian
@@ -494,6 +501,29 @@ EAPI int eolian_shutdown(void);
 EAPI Eolian_State *eolian_state_new(void);
 
 /*
+ * @brief Set the panic function for the state.
+ *
+ * When an unrecoverable error happens in an Eolian API call, the panic
+ * function is called. The default panic function for a state just prints
+ * the error message into the standard Eolian log. After the panic function
+ * is called, Eolian forcibly exits (`exit(EXIT_FAILURE)`). If you don't
+ * want this, you can override the panic function and never return from
+ * it (by doing a long jump, or throwing an exception in C++).
+ *
+ * Unrecoverable errors include cases such as internal errors and memory
+ * allocation failures. Standard parse errors etc. are not considered
+ * unrecoverable, so they are not handled using the panic mechanism.
+ *
+ * After a panic, the Eolian state is left valid; the library does its
+ * best at trying to provide it back to you in the same condition as it
+ * was before the failing call.
+ *
+ * If you set a panic function and jump, you're responsible for the error
+ * message and have to delete it with eina_stringshare_del.
+ */
+EAPI Eolian_Panic_Cb eolian_panic_cb_set(Eolian_State *state, Eolian_Panic_Cb cb);
+
+/*
  * @brief Free an Eolian state.
  *
  * You can use this to free an Eolian state.
index 7300d46..70fe7a8 100644 (file)
@@ -564,6 +564,12 @@ _hashlist_free(void *data)
    eina_list_free((Eina_List*)data);
 }
 
+static void
+_default_panic_cb(const Eolian_State *state EINA_UNUSED, const char *msg)
+{
+   _eolian_log(msg);
+}
+
 EAPI Eolian_State *
 eolian_state_new(void)
 {
@@ -571,6 +577,15 @@ eolian_state_new(void)
    if (!state)
      return NULL;
 
+   state->panic = _default_panic_cb;
+
+   if (setjmp(state->jmp_env))
+     {
+        state->panic(state, state->panic_msg);
+        eina_stringshare_del(state->panic_msg);
+        exit(EXIT_FAILURE);
+     }
+
    database_unit_init(state, &state->unit, NULL);
 
    state->filenames_eo  = eina_hash_string_small_new(free);
index 28ff787..813f3f5 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __EOLIAN_DATABASE_H
 #define __EOLIAN_DATABASE_H
 
+#include <setjmp.h>
+
 #include <Eolian.h>
 
 extern int _eolian_log_dom;
@@ -49,6 +51,10 @@ struct _Eolian_State
 {
    Eolian_Unit unit;
 
+   Eolian_Panic_Cb panic;
+   Eina_Stringshare *panic_msg;
+   jmp_buf jmp_env;
+
    Eina_Hash *filenames_eo; /* filename to full path mapping */
    Eina_Hash *filenames_eot;