586cba
From 1163da281c178359dd7e1cf1ced5c98caa600f8e Mon Sep 17 00:00:00 2001
586cba
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
586cba
Date: Mon, 25 Apr 2022 09:57:21 +0200
586cba
Subject: [PATCH 01/16] Introduce event-loop-base abstract class
586cba
586cba
RH-Author: Nicolas Saenz Julienne <nsaenzju@redhat.com>
586cba
RH-MergeRequest: 93: util/thread-pool: Expose minimum and maximum size
586cba
RH-Commit: [1/3] 5817205d8f56cc4aa98bd5963ecac54a59bad990
586cba
RH-Bugzilla: 2031024
586cba
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
586cba
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
586cba
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
586cba
586cba
Introduce the 'event-loop-base' abstract class, it'll hold the
586cba
properties common to all event loops and provide the necessary hooks for
586cba
their creation and maintenance. Then have iothread inherit from it.
586cba
586cba
EventLoopBaseClass is defined as user creatable and provides a hook for
586cba
its children to attach themselves to the user creatable class 'complete'
586cba
function. It also provides an update_params() callback to propagate
586cba
property changes onto its children.
586cba
586cba
The new 'event-loop-base' class will live in the root directory. It is
586cba
built on its own using the 'link_whole' option (there are no direct
586cba
function dependencies between the class and its children, it all happens
586cba
trough 'constructor' magic). And also imposes new compilation
586cba
dependencies:
586cba
586cba
    qom <- event-loop-base <- blockdev (iothread.c)
586cba
586cba
And in subsequent patches:
586cba
586cba
    qom <- event-loop-base <- qemuutil (util/main-loop.c)
586cba
586cba
All this forced some amount of reordering in meson.build:
586cba
586cba
 - Moved qom build definition before qemuutil. Doing it the other way
586cba
   around (i.e. moving qemuutil after qom) isn't possible as a lot of
586cba
   core libraries that live in between the two depend on it.
586cba
586cba
 - Process the 'hw' subdir earlier, as it introduces files into the
586cba
   'qom' source set.
586cba
586cba
No functional changes intended.
586cba
586cba
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
586cba
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
586cba
Acked-by: Markus Armbruster <armbru@redhat.com>
586cba
Message-id: 20220425075723.20019-2-nsaenzju@redhat.com
586cba
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
586cba
(cherry picked from commit 7d5983e3c8c40b1d0668faba31d79905c4fadd7d)
586cba
---
586cba
 event-loop-base.c                | 104 +++++++++++++++++++++++++++++++
586cba
 include/sysemu/event-loop-base.h |  36 +++++++++++
586cba
 include/sysemu/iothread.h        |   6 +-
586cba
 iothread.c                       |  65 ++++++-------------
586cba
 meson.build                      |  23 ++++---
586cba
 qapi/qom.json                    |  22 +++++--
586cba
 6 files changed, 192 insertions(+), 64 deletions(-)
586cba
 create mode 100644 event-loop-base.c
586cba
 create mode 100644 include/sysemu/event-loop-base.h
586cba
586cba
diff --git a/event-loop-base.c b/event-loop-base.c
586cba
new file mode 100644
586cba
index 0000000000..a924c73a7c
586cba
--- /dev/null
586cba
+++ b/event-loop-base.c
586cba
@@ -0,0 +1,104 @@
586cba
+/*
586cba
+ * QEMU event-loop base
586cba
+ *
586cba
+ * Copyright (C) 2022 Red Hat Inc
586cba
+ *
586cba
+ * Authors:
586cba
+ *  Stefan Hajnoczi <stefanha@redhat.com>
586cba
+ *  Nicolas Saenz Julienne <nsaenzju@redhat.com>
586cba
+ *
586cba
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
586cba
+ * See the COPYING file in the top-level directory.
586cba
+ */
586cba
+
586cba
+#include "qemu/osdep.h"
586cba
+#include "qom/object_interfaces.h"
586cba
+#include "qapi/error.h"
586cba
+#include "sysemu/event-loop-base.h"
586cba
+
586cba
+typedef struct {
586cba
+    const char *name;
586cba
+    ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
586cba
+} EventLoopBaseParamInfo;
586cba
+
586cba
+static EventLoopBaseParamInfo aio_max_batch_info = {
586cba
+    "aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
586cba
+};
586cba
+
586cba
+static void event_loop_base_get_param(Object *obj, Visitor *v,
586cba
+        const char *name, void *opaque, Error **errp)
586cba
+{
586cba
+    EventLoopBase *event_loop_base = EVENT_LOOP_BASE(obj);
586cba
+    EventLoopBaseParamInfo *info = opaque;
586cba
+    int64_t *field = (void *)event_loop_base + info->offset;
586cba
+
586cba
+    visit_type_int64(v, name, field, errp);
586cba
+}
586cba
+
586cba
+static void event_loop_base_set_param(Object *obj, Visitor *v,
586cba
+        const char *name, void *opaque, Error **errp)
586cba
+{
586cba
+    EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj);
586cba
+    EventLoopBase *base = EVENT_LOOP_BASE(obj);
586cba
+    EventLoopBaseParamInfo *info = opaque;
586cba
+    int64_t *field = (void *)base + info->offset;
586cba
+    int64_t value;
586cba
+
586cba
+    if (!visit_type_int64(v, name, &value, errp)) {
586cba
+        return;
586cba
+    }
586cba
+
586cba
+    if (value < 0) {
586cba
+        error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
586cba
+                   info->name, INT64_MAX);
586cba
+        return;
586cba
+    }
586cba
+
586cba
+    *field = value;
586cba
+
586cba
+    if (bc->update_params) {
586cba
+        bc->update_params(base, errp);
586cba
+    }
586cba
+
586cba
+    return;
586cba
+}
586cba
+
586cba
+static void event_loop_base_complete(UserCreatable *uc, Error **errp)
586cba
+{
586cba
+    EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
586cba
+    EventLoopBase *base = EVENT_LOOP_BASE(uc);
586cba
+
586cba
+    if (bc->init) {
586cba
+        bc->init(base, errp);
586cba
+    }
586cba
+}
586cba
+
586cba
+static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
586cba
+{
586cba
+    UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
586cba
+    ucc->complete = event_loop_base_complete;
586cba
+
586cba
+    object_class_property_add(klass, "aio-max-batch", "int",
586cba
+                              event_loop_base_get_param,
586cba
+                              event_loop_base_set_param,
586cba
+                              NULL, &aio_max_batch_info);
586cba
+}
586cba
+
586cba
+static const TypeInfo event_loop_base_info = {
586cba
+    .name = TYPE_EVENT_LOOP_BASE,
586cba
+    .parent = TYPE_OBJECT,
586cba
+    .instance_size = sizeof(EventLoopBase),
586cba
+    .class_size = sizeof(EventLoopBaseClass),
586cba
+    .class_init = event_loop_base_class_init,
586cba
+    .abstract = true,
586cba
+    .interfaces = (InterfaceInfo[]) {
586cba
+        { TYPE_USER_CREATABLE },
586cba
+        { }
586cba
+    }
586cba
+};
586cba
+
586cba
+static void register_types(void)
586cba
+{
586cba
+    type_register_static(&event_loop_base_info);
586cba
+}
586cba
+type_init(register_types);
586cba
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
586cba
new file mode 100644
586cba
index 0000000000..8e77d8b69f
586cba
--- /dev/null
586cba
+++ b/include/sysemu/event-loop-base.h
586cba
@@ -0,0 +1,36 @@
586cba
+/*
586cba
+ * QEMU event-loop backend
586cba
+ *
586cba
+ * Copyright (C) 2022 Red Hat Inc
586cba
+ *
586cba
+ * Authors:
586cba
+ *  Nicolas Saenz Julienne <nsaenzju@redhat.com>
586cba
+ *
586cba
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
586cba
+ * See the COPYING file in the top-level directory.
586cba
+ */
586cba
+#ifndef QEMU_EVENT_LOOP_BASE_H
586cba
+#define QEMU_EVENT_LOOP_BASE_H
586cba
+
586cba
+#include "qom/object.h"
586cba
+#include "block/aio.h"
586cba
+#include "qemu/typedefs.h"
586cba
+
586cba
+#define TYPE_EVENT_LOOP_BASE         "event-loop-base"
586cba
+OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass,
586cba
+                    EVENT_LOOP_BASE)
586cba
+
586cba
+struct EventLoopBaseClass {
586cba
+    ObjectClass parent_class;
586cba
+
586cba
+    void (*init)(EventLoopBase *base, Error **errp);
586cba
+    void (*update_params)(EventLoopBase *base, Error **errp);
586cba
+};
586cba
+
586cba
+struct EventLoopBase {
586cba
+    Object parent;
586cba
+
586cba
+    /* AioContext AIO engine parameters */
586cba
+    int64_t aio_max_batch;
586cba
+};
586cba
+#endif
586cba
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
586cba
index 7f714bd136..8f8601d6ab 100644
586cba
--- a/include/sysemu/iothread.h
586cba
+++ b/include/sysemu/iothread.h
586cba
@@ -17,11 +17,12 @@
586cba
 #include "block/aio.h"
586cba
 #include "qemu/thread.h"
586cba
 #include "qom/object.h"
586cba
+#include "sysemu/event-loop-base.h"
586cba
 
586cba
 #define TYPE_IOTHREAD "iothread"
586cba
 
586cba
 struct IOThread {
586cba
-    Object parent_obj;
586cba
+    EventLoopBase parent_obj;
586cba
 
586cba
     QemuThread thread;
586cba
     AioContext *ctx;
586cba
@@ -37,9 +38,6 @@ struct IOThread {
586cba
     int64_t poll_max_ns;
586cba
     int64_t poll_grow;
586cba
     int64_t poll_shrink;
586cba
-
586cba
-    /* AioContext AIO engine parameters */
586cba
-    int64_t aio_max_batch;
586cba
 };
586cba
 typedef struct IOThread IOThread;
586cba
 
586cba
diff --git a/iothread.c b/iothread.c
586cba
index 0f98af0f2a..8fa2f3bfb8 100644
586cba
--- a/iothread.c
586cba
+++ b/iothread.c
586cba
@@ -17,6 +17,7 @@
586cba
 #include "qemu/module.h"
586cba
 #include "block/aio.h"
586cba
 #include "block/block.h"
586cba
+#include "sysemu/event-loop-base.h"
586cba
 #include "sysemu/iothread.h"
586cba
 #include "qapi/error.h"
586cba
 #include "qapi/qapi-commands-misc.h"
586cba
@@ -152,10 +153,15 @@ static void iothread_init_gcontext(IOThread *iothread)
586cba
     iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
586cba
 }
586cba
 
586cba
-static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
586cba
+static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
586cba
 {
586cba
+    IOThread *iothread = IOTHREAD(base);
586cba
     ERRP_GUARD();
586cba
 
586cba
+    if (!iothread->ctx) {
586cba
+        return;
586cba
+    }
586cba
+
586cba
     aio_context_set_poll_params(iothread->ctx,
586cba
                                 iothread->poll_max_ns,
586cba
                                 iothread->poll_grow,
586cba
@@ -166,14 +172,15 @@ static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
586cba
     }
586cba
 
586cba
     aio_context_set_aio_params(iothread->ctx,
586cba
-                               iothread->aio_max_batch,
586cba
+                               iothread->parent_obj.aio_max_batch,
586cba
                                errp);
586cba
 }
586cba
 
586cba
-static void iothread_complete(UserCreatable *obj, Error **errp)
586cba
+
586cba
+static void iothread_init(EventLoopBase *base, Error **errp)
586cba
 {
586cba
     Error *local_error = NULL;
586cba
-    IOThread *iothread = IOTHREAD(obj);
586cba
+    IOThread *iothread = IOTHREAD(base);
586cba
     char *thread_name;
586cba
 
586cba
     iothread->stopping = false;
586cba
@@ -189,7 +196,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp)
586cba
      */
586cba
     iothread_init_gcontext(iothread);
586cba
 
586cba
-    iothread_set_aio_context_params(iothread, &local_error);
586cba
+    iothread_set_aio_context_params(base, &local_error);
586cba
     if (local_error) {
586cba
         error_propagate(errp, local_error);
586cba
         aio_context_unref(iothread->ctx);
586cba
@@ -201,7 +208,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp)
586cba
      * to inherit.
586cba
      */
586cba
     thread_name = g_strdup_printf("IO %s",
586cba
-                        object_get_canonical_path_component(OBJECT(obj)));
586cba
+                        object_get_canonical_path_component(OBJECT(base)));
586cba
     qemu_thread_create(&iothread->thread, thread_name, iothread_run,
586cba
                        iothread, QEMU_THREAD_JOINABLE);
586cba
     g_free(thread_name);
586cba
@@ -226,9 +233,6 @@ static IOThreadParamInfo poll_grow_info = {
586cba
 static IOThreadParamInfo poll_shrink_info = {
586cba
     "poll-shrink", offsetof(IOThread, poll_shrink),
586cba
 };
586cba
-static IOThreadParamInfo aio_max_batch_info = {
586cba
-    "aio-max-batch", offsetof(IOThread, aio_max_batch),
586cba
-};
586cba
 
586cba
 static void iothread_get_param(Object *obj, Visitor *v,
586cba
         const char *name, IOThreadParamInfo *info, Error **errp)
586cba
@@ -288,35 +292,12 @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
586cba
     }
586cba
 }
586cba
 
586cba
-static void iothread_get_aio_param(Object *obj, Visitor *v,
586cba
-        const char *name, void *opaque, Error **errp)
586cba
-{
586cba
-    IOThreadParamInfo *info = opaque;
586cba
-
586cba
-    iothread_get_param(obj, v, name, info, errp);
586cba
-}
586cba
-
586cba
-static void iothread_set_aio_param(Object *obj, Visitor *v,
586cba
-        const char *name, void *opaque, Error **errp)
586cba
-{
586cba
-    IOThread *iothread = IOTHREAD(obj);
586cba
-    IOThreadParamInfo *info = opaque;
586cba
-
586cba
-    if (!iothread_set_param(obj, v, name, info, errp)) {
586cba
-        return;
586cba
-    }
586cba
-
586cba
-    if (iothread->ctx) {
586cba
-        aio_context_set_aio_params(iothread->ctx,
586cba
-                                   iothread->aio_max_batch,
586cba
-                                   errp);
586cba
-    }
586cba
-}
586cba
-
586cba
 static void iothread_class_init(ObjectClass *klass, void *class_data)
586cba
 {
586cba
-    UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
586cba
-    ucc->complete = iothread_complete;
586cba
+    EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
586cba
+
586cba
+    bc->init = iothread_init;
586cba
+    bc->update_params = iothread_set_aio_context_params;
586cba
 
586cba
     object_class_property_add(klass, "poll-max-ns", "int",
586cba
                               iothread_get_poll_param,
586cba
@@ -330,23 +311,15 @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
586cba
                               iothread_get_poll_param,
586cba
                               iothread_set_poll_param,
586cba
                               NULL, &poll_shrink_info);
586cba
-    object_class_property_add(klass, "aio-max-batch", "int",
586cba
-                              iothread_get_aio_param,
586cba
-                              iothread_set_aio_param,
586cba
-                              NULL, &aio_max_batch_info);
586cba
 }
586cba
 
586cba
 static const TypeInfo iothread_info = {
586cba
     .name = TYPE_IOTHREAD,
586cba
-    .parent = TYPE_OBJECT,
586cba
+    .parent = TYPE_EVENT_LOOP_BASE,
586cba
     .class_init = iothread_class_init,
586cba
     .instance_size = sizeof(IOThread),
586cba
     .instance_init = iothread_instance_init,
586cba
     .instance_finalize = iothread_instance_finalize,
586cba
-    .interfaces = (InterfaceInfo[]) {
586cba
-        {TYPE_USER_CREATABLE},
586cba
-        {}
586cba
-    },
586cba
 };
586cba
 
586cba
 static void iothread_register_types(void)
586cba
@@ -383,7 +356,7 @@ static int query_one_iothread(Object *object, void *opaque)
586cba
     info->poll_max_ns = iothread->poll_max_ns;
586cba
     info->poll_grow = iothread->poll_grow;
586cba
     info->poll_shrink = iothread->poll_shrink;
586cba
-    info->aio_max_batch = iothread->aio_max_batch;
586cba
+    info->aio_max_batch = iothread->parent_obj.aio_max_batch;
586cba
 
586cba
     QAPI_LIST_APPEND(*tail, info);
586cba
     return 0;
586cba
diff --git a/meson.build b/meson.build
586cba
index 6f7e430f0f..b9c919a55e 100644
586cba
--- a/meson.build
586cba
+++ b/meson.build
586cba
@@ -2804,6 +2804,7 @@ subdir('qom')
586cba
 subdir('authz')
586cba
 subdir('crypto')
586cba
 subdir('ui')
586cba
+subdir('hw')
586cba
 
586cba
 
586cba
 if enable_modules
586cba
@@ -2811,6 +2812,18 @@ if enable_modules
586cba
   modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO')
586cba
 endif
586cba
 
586cba
+qom_ss = qom_ss.apply(config_host, strict: false)
586cba
+libqom = static_library('qom', qom_ss.sources() + genh,
586cba
+                        dependencies: [qom_ss.dependencies()],
586cba
+                        name_suffix: 'fa')
586cba
+qom = declare_dependency(link_whole: libqom)
586cba
+
586cba
+event_loop_base = files('event-loop-base.c')
586cba
+event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh,
586cba
+                                 build_by_default: true)
586cba
+event_loop_base = declare_dependency(link_whole: event_loop_base,
586cba
+                                     dependencies: [qom])
586cba
+
586cba
 stub_ss = stub_ss.apply(config_all, strict: false)
586cba
 
586cba
 util_ss.add_all(trace_ss)
586cba
@@ -2897,7 +2910,6 @@ subdir('monitor')
586cba
 subdir('net')
586cba
 subdir('replay')
586cba
 subdir('semihosting')
586cba
-subdir('hw')
586cba
 subdir('tcg')
586cba
 subdir('fpu')
586cba
 subdir('accel')
586cba
@@ -3022,13 +3034,6 @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
586cba
                              capture: true,
586cba
                              command: [undefsym, nm, '@INPUT@'])
586cba
 
586cba
-qom_ss = qom_ss.apply(config_host, strict: false)
586cba
-libqom = static_library('qom', qom_ss.sources() + genh,
586cba
-                        dependencies: [qom_ss.dependencies()],
586cba
-                        name_suffix: 'fa')
586cba
-
586cba
-qom = declare_dependency(link_whole: libqom)
586cba
-
586cba
 authz_ss = authz_ss.apply(config_host, strict: false)
586cba
 libauthz = static_library('authz', authz_ss.sources() + genh,
586cba
                           dependencies: [authz_ss.dependencies()],
586cba
@@ -3081,7 +3086,7 @@ libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
586cba
                              build_by_default: false)
586cba
 
586cba
 blockdev = declare_dependency(link_whole: [libblockdev],
586cba
-                              dependencies: [block])
586cba
+                              dependencies: [block, event_loop_base])
586cba
 
586cba
 qmp_ss = qmp_ss.apply(config_host, strict: false)
586cba
 libqmp = static_library('qmp', qmp_ss.sources() + genh,
586cba
diff --git a/qapi/qom.json b/qapi/qom.json
586cba
index eeb5395ff3..a2439533c5 100644
586cba
--- a/qapi/qom.json
586cba
+++ b/qapi/qom.json
586cba
@@ -499,6 +499,20 @@
586cba
             '*repeat': 'bool',
586cba
             '*grab-toggle': 'GrabToggleKeys' } }
586cba
 
586cba
+##
586cba
+# @EventLoopBaseProperties:
586cba
+#
586cba
+# Common properties for event loops
586cba
+#
586cba
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
586cba
+#                 0 means that the engine will use its default.
586cba
+#                 (default: 0)
586cba
+#
586cba
+# Since: 7.1
586cba
+##
586cba
+{ 'struct': 'EventLoopBaseProperties',
586cba
+  'data': { '*aio-max-batch': 'int' } }
586cba
+
586cba
 ##
586cba
 # @IothreadProperties:
586cba
 #
586cba
@@ -516,17 +530,15 @@
586cba
 #               algorithm detects it is spending too long polling without
586cba
 #               encountering events. 0 selects a default behaviour (default: 0)
586cba
 #
586cba
-# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
586cba
-#                 0 means that the engine will use its default
586cba
-#                 (default:0, since 6.1)
586cba
+# The @aio-max-batch option is available since 6.1.
586cba
 #
586cba
 # Since: 2.0
586cba
 ##
586cba
 { 'struct': 'IothreadProperties',
586cba
+  'base': 'EventLoopBaseProperties',
586cba
   'data': { '*poll-max-ns': 'int',
586cba
             '*poll-grow': 'int',
586cba
-            '*poll-shrink': 'int',
586cba
-            '*aio-max-batch': 'int' } }
586cba
+            '*poll-shrink': 'int' } }
586cba
 
586cba
 ##
586cba
 # @MemoryBackendProperties:
586cba
-- 
586cba
2.31.1
586cba