[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 017/114] module: add before/after hooks and module_call_init_fn



module_call_init just walks the list. Add register_module_hooks
so one init type can wrap that walk with before and after
ModuleInitHook callbacks, and add module_call_init_fn so a single
function takes the same path.

module_call_init passes MODULE_INIT_PHASE_ON. A DSO or
module_call_init_fn passes DSO_BEFORE until module_call_init
finishes, then DSO_AFTER.

Signed-off-by: Yonggang Luo <luoyonggang@xxxxxxxxx>
---
 include/qemu/module.h | 18 +++++++++++
 util/module.c         | 70 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/include/qemu/module.h b/include/qemu/module.h
index 34e05c75348..c10e32731fa 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -60,6 +60,20 @@ typedef enum {
 
 typedef void (ModuleInitFn)(void);
 
+/*
+ * Where one module_init_run sits relative to module_call_init().
+ * DSO_BEFORE: a DSO or module_call_init_fn before module_call_init().
+ * ON: module_call_init() itself.
+ * DSO_AFTER: a DSO or module_call_init_fn after module_call_init().
+ */
+typedef enum ModuleInitPhase {
+    MODULE_INIT_PHASE_DSO_BEFORE,
+    MODULE_INIT_PHASE_ON,
+    MODULE_INIT_PHASE_DSO_AFTER,
+} ModuleInitPhase;
+
+typedef bool (ModuleInitHook)(ModuleInitPhase phase, Error **errp);
+
 typedef struct ModuleEntry {
     ModuleInitFn *init;
     QTAILQ_ENTRY(ModuleEntry) node;
@@ -82,6 +96,10 @@ void register_module_init(ModuleEntry *e, module_init_type 
type);
 void register_dso_module_init(ModuleEntry *e, module_init_type type);
 
 void module_call_init(module_init_type type);
+void module_call_init_fn(module_init_type type, ModuleInitFn *init, Error 
**errp);
+
+void register_module_hooks(module_init_type type,
+                           ModuleInitHook *before, ModuleInitHook *after);
 
 /*
  * module_load: attempt to load a module from a set of directories
diff --git a/util/module.c b/util/module.c
index 6c5980542f6..a007ecb53a6 100644
--- a/util/module.c
+++ b/util/module.c
@@ -32,6 +32,8 @@ typedef QTAILQ_HEAD(, ModuleEntry) ModuleEntryList;
 typedef struct ModuleInit
 {
     module_init_type type;
+    ModuleInitHook *before;
+    ModuleInitHook *after;
     ModuleEntryList list;
     ModuleEntryList dso_list;
     bool done;
@@ -88,14 +90,54 @@ void register_dso_module_init(ModuleEntry *e, 
module_init_type type)
     module_init_add(&find_type(type)->dso_list, e);
 }
 
-static void module_init_run(ModuleInit *m, ModuleEntryList *list)
+/**
+ * register_module_hooks:
+ * @type: init list
+ * @before: runs before every registered init for @type
+ * @after: runs after every registered init for @type
+ *
+ * One ModuleInit holds both callbacks so before and after stay 1:1.
+ * module_call_init(@type) passes MODULE_INIT_PHASE_ON. A DSO or
+ * module_call_init_fn passes DSO_BEFORE if module_call_init() has not
+ * finished, otherwise DSO_AFTER.
+ */
+void register_module_hooks(module_init_type type,
+                           ModuleInitHook *before, ModuleInitHook *after)
+{
+    ModuleInit *m = find_type(type);
+
+    g_assert(before);
+    g_assert(after);
+    g_assert(!m->before && !m->after);
+
+    m->before = before;
+    m->after = after;
+}
+
+static bool module_init_run(ModuleInit *m, ModuleEntryList *list, bool is_dso,
+                            Error **errp)
 {
     ModuleEntry *e;
+    ModuleInitPhase phase;
+
+    if (!is_dso) {
+        phase = MODULE_INIT_PHASE_ON;
+    } else if (m->done) {
+        phase = MODULE_INIT_PHASE_DSO_AFTER;
+    } else {
+        phase = MODULE_INIT_PHASE_DSO_BEFORE;
+    }
 
-    (void)m;
+    if (m->before && !m->before(phase, errp)) {
+        return false;
+    }
     QTAILQ_FOREACH(e, list, node) {
         e->init();
     }
+    if (m->after && !m->after(phase, errp)) {
+        return false;
+    }
+    return true;
 }
 
 void module_call_init(module_init_type type)
@@ -106,10 +148,27 @@ void module_call_init(module_init_type type)
         return;
     }
 
-    module_init_run(m, &m->list);
+    module_init_run(m, &m->list, false, &error_abort);
     m->done = true;
 }
 
+/*
+ * Run a single init through @type's before/after hooks with is_dso=true.
+ * May run before or after module_call_init.
+ */
+void module_call_init_fn(module_init_type type, ModuleInitFn *init, Error 
**errp)
+{
+    ModuleInit *m = find_type(type);
+    ModuleEntry e = {
+        .init = init,
+    };
+    ModuleEntryList list;
+
+    QTAILQ_INIT(&list);
+    QTAILQ_INSERT_TAIL(&list, &e, node);
+    module_init_run(m, &list, true, errp);
+}
+
 #ifdef CONFIG_MODULES
 
 static const QemuModinfo module_info_stub[] = { {
@@ -201,7 +260,10 @@ static bool module_load_dso(const char *fname, bool 
export_symbols,
             continue;
         }
 
-        module_init_run(m, &m->dso_list);
+        if (!module_init_run(m, &m->dso_list, true, errp)) {
+            empty_dso_lists();
+            return false;
+        }
     }
     trace_module_load_module(fname);
     empty_dso_lists();
-- 
2.52.0.windows.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.