'event-loop-base' provides basic property handling for all 'AioContext'
based event loops. So let's define a new 'MainLoopClass' that inherits
from it. This will permit tweaking the main loop's properties through
qapi as well as through the command line using the '-object' keyword[1].
Only one instance of 'MainLoopClass' might be created at any time.
'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
mark 'MainLoop' as non-deletable.
[1] For example:
-object main-loop,id=main-loop,aio-max-batch=<value>
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
Changes since v3:
- Rework qom.json
Changes since v2:
- Fix mainloop's qapi versioning
Changes since v1:
- Fix json files to differentiate between iothread and main-loop
- Use OBJECT_DECLARE_TYPE()
- Fix build dependencies
event-loop-base.c | 13 ++++++++
include/qemu/main-loop.h | 10 ++++++
include/sysemu/event-loop-base.h | 1 +
meson.build | 3 +-
qapi/qom.json | 32 +++++++++++++++---
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
6 files changed, 109 insertions(+), 6 deletions(-)
diff --git a/event-loop-base.c b/event-loop-base.c
index a924c73a7c..e7f99a6ec8 100644
--- a/event-loop-base.c
+++ b/event-loop-base.c
@@ -73,10 +73,23 @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp)
}
}
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
+{
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
+
+ if (bc->can_be_deleted) {
+ return bc->can_be_deleted(backend);
+ }
+
+ return true;
+}
+
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
ucc->complete = event_loop_base_complete;
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
object_class_property_add(klass, "aio-max-batch", "int",
event_loop_base_get_param,
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index d3750c8e76..20c9387654 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -26,9 +26,19 @@
#define QEMU_MAIN_LOOP_H
#include "block/aio.h"
+#include "qom/object.h"
+#include "sysemu/event-loop-base.h"
#define SIG_IPI SIGUSR1
+#define TYPE_MAIN_LOOP "main-loop"
+OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP)
+
+struct MainLoop {
+ EventLoopBase parent_obj;
+};
+typedef struct MainLoop MainLoop;
+
/**
* qemu_init_main_loop: Set up the process so that it can run the main loop.
*
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
index 8e77d8b69f..fced4c9fea 100644
--- a/include/sysemu/event-loop-base.h
+++ b/include/sysemu/event-loop-base.h
@@ -25,6 +25,7 @@ struct EventLoopBaseClass {
void (*init)(EventLoopBase *base, Error **errp);
void (*update_params)(EventLoopBase *base, Error **errp);
+ bool (*can_be_deleted)(EventLoopBase *base);
};
struct EventLoopBase {
diff --git a/meson.build b/meson.build
index 89aa3a2518..b8046b5b35 100644
--- a/meson.build
+++ b/meson.build
@@ -2830,7 +2830,8 @@ libqemuutil = static_library('qemuutil',
sources: util_ss.sources() + stub_ss.sources() + genh,
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
qemuutil = declare_dependency(link_with: libqemuutil,
- sources: genh + version_res)
+ sources: genh + version_res,
+ dependencies: [event_loop_base])
if have_system or have_user
decodetree = generator(find_program('scripts/decodetree.py'),
diff --git a/qapi/qom.json b/qapi/qom.json
index eeb5395ff3..e5f31c4469 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -499,6 +499,17 @@
'*repeat': 'bool',
'*grab-toggle': 'GrabToggleKeys' } }
+##
+# @EventLoopBaseProperties:
+#
+# Common properties for objects derived from EventLoopBase
+#
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
+# 0 means that the engine will use its default.
+##
+{ 'struct': 'EventLoopBaseProperties',
+ 'data': { '*aio-max-batch': 'int' } }
+
##
# @IothreadProperties:
#
@@ -516,17 +527,26 @@
# algorithm detects it is spending too long polling without
# encountering events. 0 selects a default behaviour (default: 0)
#
-# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
-# 0 means that the engine will use its default
-# (default:0, since 6.1)
+# The @aio-max-batch option is available since 6.1.
#
# Since: 2.0
##
{ 'struct': 'IothreadProperties',
+ 'base': 'EventLoopBaseProperties',
'data': { '*poll-max-ns': 'int',
'*poll-grow': 'int',
- '*poll-shrink': 'int',
- '*aio-max-batch': 'int' } }
+ '*poll-shrink': 'int' } }
+
+##
+# @MainLoopProperties:
+#
+# Properties for the main-loop object.
+#
+# Since: 7.1
+##
+{ 'struct': 'MainLoopProperties',
+ 'base': 'EventLoopBaseProperties',
+ 'data': {} }
##
# @MemoryBackendProperties:
@@ -818,6 +838,7 @@
{ 'name': 'input-linux',
'if': 'CONFIG_LINUX' },
'iothread',
+ 'main-loop',
{ 'name': 'memory-backend-epc',
'if': 'CONFIG_LINUX' },
'memory-backend-file',
@@ -883,6 +904,7 @@
'input-linux': { 'type': 'InputLinuxProperties',
'if': 'CONFIG_LINUX' },
'iothread': 'IothreadProperties',
+ 'main-loop': 'MainLoopProperties',
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
'if': 'CONFIG_LINUX' },
'memory-backend-file': 'MemoryBackendFileProperties',
diff --git a/util/main-loop.c b/util/main-loop.c
index b7b0ce4ca0..5b13f456fa 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -33,6 +33,7 @@
#include "qemu/error-report.h"
#include "qemu/queue.h"
#include "qemu/compiler.h"
+#include "qom/object.h"
#ifndef _WIN32
#include <sys/wait.h>
@@ -184,6 +185,61 @@ int qemu_init_main_loop(Error **errp)
return 0;
}
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
+{
+ if (!qemu_aio_context) {
+ error_setg(errp, "qemu aio context not ready");
+ return;
+ }
+
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
+}
+
+MainLoop *mloop;
+
+static void main_loop_init(EventLoopBase *base, Error **errp)
+{
+ MainLoop *m = MAIN_LOOP(base);
+
+ if (mloop) {
+ error_setg(errp, "only one main-loop instance allowed");
+ return;
+ }
+
+ main_loop_update_params(base, errp);
+
+ mloop = m;
+ return;
+}
+
+static bool main_loop_can_be_deleted(EventLoopBase *base)
+{
+ return false;
+}
+
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
+{
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
+
+ bc->init = main_loop_init;
+ bc->update_params = main_loop_update_params;
+ bc->can_be_deleted = main_loop_can_be_deleted;
+}
+
+static const TypeInfo main_loop_info = {
+ .name = TYPE_MAIN_LOOP,
+ .parent = TYPE_EVENT_LOOP_BASE,
+ .class_init = main_loop_class_init,
+ .instance_size = sizeof(MainLoop),
+};
+
+static void main_loop_register_types(void)
+{
+ type_register_static(&main_loop_info);
+}
+
+type_init(main_loop_register_types)
+
static int max_priority;
#ifndef _WIN32
--
2.35.1
Nicolas Saenz Julienne <nsaenzju@redhat.com> writes:
> 'event-loop-base' provides basic property handling for all 'AioContext'
> based event loops. So let's define a new 'MainLoopClass' that inherits
> from it. This will permit tweaking the main loop's properties through
> qapi as well as through the command line using the '-object' keyword[1].
> Only one instance of 'MainLoopClass' might be created at any time.
>
> 'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
> mark 'MainLoop' as non-deletable.
>
> [1] For example:
> -object main-loop,id=main-loop,aio-max-batch=<value>
>
> Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
[...]
> diff --git a/qapi/qom.json b/qapi/qom.json
> index eeb5395ff3..e5f31c4469 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -499,6 +499,17 @@
> '*repeat': 'bool',
> '*grab-toggle': 'GrabToggleKeys' } }
>
> +##
> +# @EventLoopBaseProperties:
> +#
> +# Common properties for objects derived from EventLoopBase
This makes sense as internal documentation: QAPI type
EventLoopBaseProperties is associated with C type EventLoopBase. Doc
comments are *external* documentation: they go into the QEMU QMP
Reference Manual.
What about "Common properties for event loops"?
> +#
> +# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
> +# 0 means that the engine will use its default.
Missing:
# Since: 7.1
Permit me a short digression. We add these unthinkingly, because
thinking is expensive. Even when the type isn't really part of the
external interface. The deeper problem is that we're trying to generate
documentation of the external interface from doc comments that are
written as documentation of the internal QAPI data structures. Here,
for example, we document EventLoopBaseProperties even though it is a
purely internal thing: whether we factor out common members into a base
type or not is not visible in QMP.
> +##
> +{ 'struct': 'EventLoopBaseProperties',
> + 'data': { '*aio-max-batch': 'int' } }
> +
> ##
> # @IothreadProperties:
> #
> @@ -516,17 +527,26 @@
> # algorithm detects it is spending too long polling without
> # encountering events. 0 selects a default behaviour (default: 0)
> #
> -# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
> -# 0 means that the engine will use its default
> -# (default:0, since 6.1)
> +# The @aio-max-batch option is available since 6.1.
This separates the member's "since" information from its defintion.
Can't be helped, because its defined in the base type, but the since
only applies here. Okay.
> #
> # Since: 2.0
> ##
> { 'struct': 'IothreadProperties',
> + 'base': 'EventLoopBaseProperties',
> 'data': { '*poll-max-ns': 'int',
> '*poll-grow': 'int',
> - '*poll-shrink': 'int',
> - '*aio-max-batch': 'int' } }
> + '*poll-shrink': 'int' } }
> +
> +##
> +# @MainLoopProperties:
> +#
> +# Properties for the main-loop object.
> +#
> +# Since: 7.1
> +##
> +{ 'struct': 'MainLoopProperties',
> + 'base': 'EventLoopBaseProperties',
> + 'data': {} }
The patch does two things:
1. Factor EventLoopBaseProperties out of IothreadProperties.
2. Create MainLoopProperties.
I'd split it. This is not a demand.
>
> ##
> # @MemoryBackendProperties:
> @@ -818,6 +838,7 @@
> { 'name': 'input-linux',
> 'if': 'CONFIG_LINUX' },
> 'iothread',
> + 'main-loop',
> { 'name': 'memory-backend-epc',
> 'if': 'CONFIG_LINUX' },
> 'memory-backend-file',
> @@ -883,6 +904,7 @@
> 'input-linux': { 'type': 'InputLinuxProperties',
> 'if': 'CONFIG_LINUX' },
> 'iothread': 'IothreadProperties',
> + 'main-loop': 'MainLoopProperties',
> 'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
> 'if': 'CONFIG_LINUX' },
> 'memory-backend-file': 'MemoryBackendFileProperties',
[...]
On Fri, 2022-04-22 at 13:13 +0200, Markus Armbruster wrote:
> Nicolas Saenz Julienne <nsaenzju@redhat.com> writes:
>
> > 'event-loop-base' provides basic property handling for all 'AioContext'
> > based event loops. So let's define a new 'MainLoopClass' that inherits
> > from it. This will permit tweaking the main loop's properties through
> > qapi as well as through the command line using the '-object' keyword[1].
> > Only one instance of 'MainLoopClass' might be created at any time.
> >
> > 'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
> > mark 'MainLoop' as non-deletable.
> >
> > [1] For example:
> > -object main-loop,id=main-loop,aio-max-batch=<value>
> >
> > Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
>
> [...]
>
> > diff --git a/qapi/qom.json b/qapi/qom.json
> > index eeb5395ff3..e5f31c4469 100644
> > --- a/qapi/qom.json
> > +++ b/qapi/qom.json
> > @@ -499,6 +499,17 @@
> > '*repeat': 'bool',
> > '*grab-toggle': 'GrabToggleKeys' } }
> >
> > +##
> > +# @EventLoopBaseProperties:
> > +#
> > +# Common properties for objects derived from EventLoopBase
>
> This makes sense as internal documentation: QAPI type
> EventLoopBaseProperties is associated with C type EventLoopBase. Doc
> comments are *external* documentation: they go into the QEMU QMP
> Reference Manual.
>
> What about "Common properties for event loops"?
Sounds better, yes. I'll change it.
> > +#
> > +# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
> > +# 0 means that the engine will use its default.
>
> Missing:
>
> # Since: 7.1
>
> Permit me a short digression. We add these unthinkingly, because
> thinking is expensive. Even when the type isn't really part of the
> external interface. The deeper problem is that we're trying to generate
> documentation of the external interface from doc comments that are
> written as documentation of the internal QAPI data structures. Here,
> for example, we document EventLoopBaseProperties even though it is a
> purely internal thing: whether we factor out common members into a base
> type or not is not visible in QMP.
Thanks for the explanation.
> > +##
> > +{ 'struct': 'EventLoopBaseProperties',
> > + 'data': { '*aio-max-batch': 'int' } }
> > +
> > ##
> > # @IothreadProperties:
> > #
> > @@ -516,17 +527,26 @@
> > # algorithm detects it is spending too long polling without
> > # encountering events. 0 selects a default behaviour (default: 0)
> > #
> > -# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
> > -# 0 means that the engine will use its default
> > -# (default:0, since 6.1)
> > +# The @aio-max-batch option is available since 6.1.
>
> This separates the member's "since" information from its defintion.
> Can't be helped, because its defined in the base type, but the since
> only applies here. Okay.
IIUC my compromise of having the 'since version' annotated on each externally
visible type is good, right? No need to add the info in
EventLoopBaseProperties.
> > #
> > # Since: 2.0
> > ##
> > { 'struct': 'IothreadProperties',
> > + 'base': 'EventLoopBaseProperties',
> > 'data': { '*poll-max-ns': 'int',
> > '*poll-grow': 'int',
> > - '*poll-shrink': 'int',
> > - '*aio-max-batch': 'int' } }
> > + '*poll-shrink': 'int' } }
> > +
> > +##
> > +# @MainLoopProperties:
> > +#
> > +# Properties for the main-loop object.
> > +#
> > +# Since: 7.1
> > +##
> > +{ 'struct': 'MainLoopProperties',
> > + 'base': 'EventLoopBaseProperties',
> > + 'data': {} }
>
> The patch does two things:
>
> 1. Factor EventLoopBaseProperties out of IothreadProperties.
>
> 2. Create MainLoopProperties.
>
> I'd split it. This is not a demand.
Since I'm preparing a v5 of the series, I agree it makes sense to move 1. to
the fist patch.
Thanks!
--
Nicolás Sáenz
On Fri, 2022-04-22 at 13:40 +0200, Nicolas Saenz Julienne wrote:
> > > +##
> > > +{ 'struct': 'EventLoopBaseProperties',
> > > + 'data': { '*aio-max-batch': 'int' } }
> > > +
> > > ##
> > > # @IothreadProperties:
> > > #
> > > @@ -516,17 +527,26 @@
> > > # algorithm detects it is spending too long polling without
> > > # encountering events. 0 selects a default behaviour (default: 0)
> > > #
> > > -# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
> > > -# 0 means that the engine will use its default
> > > -# (default:0, since 6.1)
> > > +# The @aio-max-batch option is available since 6.1.
> >
> > This separates the member's "since" information from its defintion.
> > Can't be helped, because its defined in the base type, but the since
> > only applies here. Okay.
>
> IIUC my compromise of having the 'since version' annotated on each externally
> visible type is good, right? No need to add the info in
> EventLoopBaseProperties.
OK, nevermind this reply. I misunderstood you. I'll:
- Add a "since 7.1" in EventLoopBaseProperties.
- Add a special comment in IothreadProperties mentioning aio-max-batch is
available since 6.1.
- Remove version info from MainLoopProperties.
Thanks!
--
Nicolás Sáenz
© 2016 - 2026 Red Hat, Inc.