[PATCH v2 09/12] qio: Prepare NetListener to use AioContext

Eric Blake posted 12 patches 1 week ago
Maintainers: Eric Blake <eblake@redhat.com>, Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>, Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>
[PATCH v2 09/12] qio: Prepare NetListener to use AioContext
Posted by Eric Blake 1 week ago
For ease of review, this patch adds an AioContext pointer to the
QIONetListener struct, the code to trace it, and refactors
listener->io_source to instead be an array of utility structs; but the
aio_context pointer is always NULL until the next patch adds an API to
set it.  There should be no semantic change in this patch.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v2: new patch, replacing the earlier "qio: Let listening sockets remember
their owning QIONetListener"
---
 include/io/net-listener.h |   6 ++-
 io/net-listener.c         | 102 ++++++++++++++++++++++++++------------
 io/trace-events           |   6 +--
 3 files changed, 76 insertions(+), 38 deletions(-)

diff --git a/include/io/net-listener.h b/include/io/net-listener.h
index 2605d6aae1e..7188721cb34 100644
--- a/include/io/net-listener.h
+++ b/include/io/net-listener.h
@@ -28,6 +28,7 @@
 OBJECT_DECLARE_SIMPLE_TYPE(QIONetListener,
                            QIO_NET_LISTENER)

+typedef struct QIONetListenerSource QIONetListenerSource;

 typedef void (*QIONetListenerClientFunc)(QIONetListener *listener,
                                          QIOChannelSocket *sioc,
@@ -47,10 +48,11 @@ struct QIONetListener {
     Object parent;

     char *name;
-    QIOChannelSocket **sioc;
-    GSource **io_source;
+    QIONetListenerSource **source;
     size_t nsioc;
+    /* At most one of context or aio_context will be set */
     GMainContext *context;
+    AioContext *aio_context;

     bool connected;

diff --git a/io/net-listener.c b/io/net-listener.c
index 83c977ecca2..ebc61f81ed6 100644
--- a/io/net-listener.c
+++ b/io/net-listener.c
@@ -23,8 +23,15 @@
 #include "io/dns-resolver.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
+#include "qemu/main-loop.h"
 #include "trace.h"

+struct QIONetListenerSource {
+    QIOChannelSocket *sioc;
+    GSource *io_source;
+    QIONetListener *listener;
+};
+
 QIONetListener *qio_net_listener_new(void)
 {
     return QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER));
@@ -52,7 +59,7 @@ static gboolean qio_net_listener_channel_func(QIOChannel *ioc,
     }

     trace_qio_net_listener_callback(listener, listener->io_func,
-                                    listener->context);
+                                    listener->context, listener->aio_context);
     if (listener->io_func) {
         object_ref(OBJECT(listener));
         listener->io_func(listener, sioc, listener->io_data);
@@ -121,15 +128,25 @@ qio_net_listener_watch(QIONetListener *listener, size_t i, const char *caller)
     }

     trace_qio_net_listener_watch(listener, listener->io_func,
-                                 listener->context, caller);
+                                 listener->context, listener->aio_context,
+                                 caller);
     if (i == 0) {
         object_ref(OBJECT(listener));
     }
     for ( ; i < listener->nsioc; i++) {
-        listener->io_source[i] = qio_channel_add_watch_source(
-            QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
-            qio_net_listener_channel_func,
-            listener, NULL, listener->context);
+        if (!listener->aio_context) {
+            /*
+             * The user passed a GMainContext with the async callback;
+             * they plan on running the default or their own g_main_loop.
+             */
+            listener->source[i]->io_source = qio_channel_add_watch_source(
+                QIO_CHANNEL(listener->source[i]->sioc), G_IO_IN,
+                qio_net_listener_channel_func,
+                listener, NULL, listener->context);
+        } else {
+            /* The user passed an AioContext. Not supported yet. */
+            g_assert_not_reached();
+        }
     }
 }

@@ -143,12 +160,17 @@ qio_net_listener_unwatch(QIONetListener *listener, const char *caller)
     }

     trace_qio_net_listener_unwatch(listener, listener->io_func,
-                                   listener->context, caller);
+                                   listener->context, listener->aio_context,
+                                   caller);
     for (i = 0; i < listener->nsioc; i++) {
-        if (listener->io_source[i]) {
-            g_source_destroy(listener->io_source[i]);
-            g_source_unref(listener->io_source[i]);
-            listener->io_source[i] = NULL;
+        if (!listener->aio_context) {
+            if (listener->source[i]->io_source) {
+                g_source_destroy(listener->source[i]->io_source);
+                g_source_unref(listener->source[i]->io_source);
+                listener->source[i]->io_source = NULL;
+            }
+        } else {
+            g_assert_not_reached();
         }
     }
     object_unref(OBJECT(listener));
@@ -161,13 +183,12 @@ void qio_net_listener_add(QIONetListener *listener,
         qio_channel_set_name(QIO_CHANNEL(sioc), listener->name);
     }

-    listener->sioc = g_renew(QIOChannelSocket *, listener->sioc,
-                             listener->nsioc + 1);
-    listener->io_source = g_renew(typeof(listener->io_source[0]),
-                                  listener->io_source,
-                                  listener->nsioc + 1);
-    listener->sioc[listener->nsioc] = sioc;
-    listener->io_source[listener->nsioc] = NULL;
+    listener->source = g_renew(typeof(listener->source[0]),
+                               listener->source,
+                               listener->nsioc + 1);
+    listener->source[listener->nsioc] = g_new0(QIONetListenerSource, 1);
+    listener->source[listener->nsioc]->sioc = sioc;
+    listener->source[listener->nsioc]->listener = listener;

     object_ref(OBJECT(sioc));
     listener->connected = true;
@@ -177,14 +198,17 @@ void qio_net_listener_add(QIONetListener *listener,
 }


-void qio_net_listener_set_client_func_full(QIONetListener *listener,
-                                           QIONetListenerClientFunc func,
-                                           gpointer data,
-                                           GDestroyNotify notify,
-                                           GMainContext *context)
+static void
+qio_net_listener_set_client_func_internal(QIONetListener *listener,
+                                          QIONetListenerClientFunc func,
+                                          gpointer data,
+                                          GDestroyNotify notify,
+                                          GMainContext *context,
+                                          AioContext *aio_context)
 {
     if (listener->io_func == func && listener->io_data == data &&
-        listener->io_notify == notify && listener->context == context) {
+        listener->io_notify == notify && listener->context == context &&
+        listener->aio_context == aio_context) {
         return;
     }

@@ -196,17 +220,28 @@ void qio_net_listener_set_client_func_full(QIONetListener *listener,
     listener->io_data = data;
     listener->io_notify = notify;
     listener->context = context;
+    listener->aio_context = aio_context;

     qio_net_listener_watch(listener, 0, "set_client_func");
 }

+void qio_net_listener_set_client_func_full(QIONetListener *listener,
+                                           QIONetListenerClientFunc func,
+                                           gpointer data,
+                                           GDestroyNotify notify,
+                                           GMainContext *context)
+{
+    qio_net_listener_set_client_func_internal(listener, func, data,
+                                              notify, context, NULL);
+}
+
 void qio_net_listener_set_client_func(QIONetListener *listener,
                                       QIONetListenerClientFunc func,
                                       gpointer data,
                                       GDestroyNotify notify)
 {
-    qio_net_listener_set_client_func_full(listener, func, data,
-                                          notify, NULL);
+    qio_net_listener_set_client_func_internal(listener, func, data,
+                                              notify, NULL, NULL);
 }

 struct QIONetListenerClientWaitData {
@@ -253,8 +288,8 @@ QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener)

     sources = g_new0(GSource *, listener->nsioc);
     for (i = 0; i < listener->nsioc; i++) {
-        sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]),
-                                              G_IO_IN);
+        sources[i] = qio_channel_create_watch(
+            QIO_CHANNEL(listener->source[i]->sioc), G_IO_IN);

         g_source_set_callback(sources[i],
                               (GSourceFunc)qio_net_listener_wait_client_func,
@@ -287,7 +322,7 @@ void qio_net_listener_disconnect(QIONetListener *listener)

     qio_net_listener_unwatch(listener, "disconnect");
     for (i = 0; i < listener->nsioc; i++) {
-        qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL);
+        qio_channel_close(QIO_CHANNEL(listener->source[i]->sioc), NULL);
     }
     listener->connected = false;
 }
@@ -308,8 +343,9 @@ QIOChannelSocket *qio_net_listener_sioc(QIONetListener *listener, size_t n)
     if (n > listener->nsioc) {
         return NULL;
     }
-    return listener->sioc[n];
+    return listener->source[n]->sioc;
 }
+
 static void qio_net_listener_finalize(Object *obj)
 {
     QIONetListener *listener = QIO_NET_LISTENER(obj);
@@ -321,10 +357,10 @@ static void qio_net_listener_finalize(Object *obj)
     }

     for (i = 0; i < listener->nsioc; i++) {
-        object_unref(OBJECT(listener->sioc[i]));
+        object_unref(OBJECT(listener->source[i]->sioc));
+        g_free(listener->source[i]);
     }
-    g_free(listener->io_source);
-    g_free(listener->sioc);
+    g_free(listener->source);
     g_free(listener->name);
 }

diff --git a/io/trace-events b/io/trace-events
index 0cb77d579b6..ec91453335a 100644
--- a/io/trace-events
+++ b/io/trace-events
@@ -74,6 +74,6 @@ qio_channel_command_abort(void *ioc, int pid) "Command abort ioc=%p pid=%d"
 qio_channel_command_wait(void *ioc, int pid, int ret, int status) "Command abort ioc=%p pid=%d ret=%d status=%d"

 # net-listener.c
-qio_net_listener_watch(void *listener, void *func, void *ctx, const char *extra) "Net listener=%p watch enabled func=%p ctx=%p by %s"
-qio_net_listener_unwatch(void *listener, void *func, void *ctx, const char *extra) "Net listener=%p watch disabled func=%p ctx=%p by %s"
-qio_net_listener_callback(void *listener, void *func, void *ctx) "Net listener=%p callback forwarding to func=%p ctx=%p"
+qio_net_listener_watch(void *listener, void *func, void *gctx, void *actx, const char *extra) "Net listener=%p watch enabled func=%p ctx=%p/%p by %s"
+qio_net_listener_unwatch(void *listener, void *func, void *gctx, void *actx, const char *extra) "Net listener=%p watch disabled func=%p ctx=%p/%p by %s"
+qio_net_listener_callback(void *listener, void *func, void *gctx, void *actx) "Net listener=%p callback forwarding to func=%p ctx=%p/%p"
-- 
2.51.1
Re: [PATCH v2 09/12] qio: Prepare NetListener to use AioContext
Posted by Daniel P. Berrangé 4 days, 10 hours ago
On Sat, Nov 08, 2025 at 04:59:30PM -0600, Eric Blake wrote:
> For ease of review, this patch adds an AioContext pointer to the
> QIONetListener struct, the code to trace it, and refactors
> listener->io_source to instead be an array of utility structs; but the
> aio_context pointer is always NULL until the next patch adds an API to
> set it.  There should be no semantic change in this patch.
> 
> Signed-off-by: Eric Blake <eblake@redhat.com>
> 
> ---
> v2: new patch, replacing the earlier "qio: Let listening sockets remember
> their owning QIONetListener"
> ---
>  include/io/net-listener.h |   6 ++-
>  io/net-listener.c         | 102 ++++++++++++++++++++++++++------------
>  io/trace-events           |   6 +--
>  3 files changed, 76 insertions(+), 38 deletions(-)

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|