On Tue, May 12, 2026 at 2:54 AM Stefan Hajnoczi <[email protected]> wrote:
>
> On Mon, May 11, 2026 at 10:04:05PM +0800, Zhang Chen wrote:
> > Introduce iothread_get_aio_context() with a 'holder' argument and its
> > counterpart iothread_put_aio_context().
> >
> > Previously, users of an IOThread's AioContext did not explicitly
> > record their identity, making it difficult to debug which devices or
> > subsystems were pinning an IOThread.
> >
> > This patch enhances the reference counting mechanism by:
> > 1. Automatically incrementing the object reference count when a context
> > is retrieved.
> > 2. Tracking holders by name using iothread_ref() and iothread_unref().
> >
> > In iothread_instance_finalize(), we now retrieve the source name from
> > the GMainContext to correctly unref the initial internal holder.
> >
> > Signed-off-by: Zhang Chen <[email protected]>
> > ---
> > include/system/iothread.h | 3 +++
> > iothread.c | 33 +++++++++++++++++++++++++++++----
> > 2 files changed, 32 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/system/iothread.h b/include/system/iothread.h
> > index 2871b06edc..313ef61124 100644
> > --- a/include/system/iothread.h
> > +++ b/include/system/iothread.h
> > @@ -70,6 +70,9 @@ DECLARE_INSTANCE_CHECKER(IOThread, IOTHREAD,
> > char *iothread_get_id(IOThread *iothread);
> > IOThread *iothread_by_id(const char *id);
> > AioContext *iothread_get_aio_context(IOThread *iothread);
> > +AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
> > + const char *holder);
> > +void iothread_put_aio_context(IOThread *iothread, const char *holder);
> > GMainContext *iothread_get_g_main_context(IOThread *iothread);
> >
> > /*
> > diff --git a/iothread.c b/iothread.c
> > index b805e4f97d..5d6f46d286 100644
> > --- a/iothread.c
> > +++ b/iothread.c
> > @@ -44,6 +44,12 @@ static void iothread_ref(IOThread *iothread, const char
> > *holder)
> > }
> >
> > iothread->holders = g_list_prepend(iothread->holders, h);
> > +
> > + /*
> > + * This guarantees that the IOThread and its AioContext remain alive
> > + * as long as there is a holder.
> > + */
> > + object_ref(OBJECT(iothread));
> > }
> >
> > static int iothread_holder_compare(gconstpointer a, gconstpointer b)
> > @@ -83,6 +89,8 @@ static void iothread_unref(IOThread *iothread, const char
> > *holder)
> > IoThreadHolder *h = (IoThreadHolder *)link->data;
> > qapi_free_IoThreadHolder(h);
> > iothread->holders = g_list_delete_link(iothread->holders, link);
> > +
> > + object_unref(OBJECT(iothread));
> > }
> >
> > static void *iothread_run(void *opaque)
> > @@ -200,7 +208,7 @@ static void iothread_init_gcontext(IOThread *iothread,
> > const char *thread_name)
> > g_autofree char *name = g_strdup_printf("%s aio-context", thread_name);
> >
> > iothread->worker_context = g_main_context_new();
> > - source = aio_get_g_source(iothread_get_aio_context(iothread));
> > + source = aio_get_g_source(iothread->ctx);
> > g_source_set_name(source, name);
> > g_source_attach(source, iothread->worker_context);
> > g_source_unref(source);
> > @@ -419,13 +427,30 @@ char *iothread_get_id(IOThread *iothread)
> >
> > AioContext *iothread_get_aio_context(IOThread *iothread)
> > {
> > - /* Remove in next patch for build */
> > - iothread_ref(iothread, "tmp");
> > - iothread_unref(iothread, "tmp");
> > + return iothread->ctx;
> > +}
> > +
> > +AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
> > + const char *holder)
> > +{
> > + /*
> > + * In some cases, iothread user need the ctx to clearup other resource.
> > + * When holder is empty, back to the legacy way.
>
> Let's avoid referring to the legacy way. Developers working on the code
> after this series has been merged may not know what the legacy way was.
>
> If an API to fetch iothread->ctx without taking a reference is needed,
> then it should probably be a separate API.
> iothread_ref_and_get_aio_context() calls should have a matching
> iothread_put_aio_context() call. That's not the case when
> iothread_ref_and_get_aio_context(iothread, NULL) is allowed.
Sorry, my comments are out of date, for the V7 patch, the legacy
way has been completely abandoned(you can double check it in the patch 14/14).
I will remove this comments in the next version.
Thanks
Chen
>
> > + */
> > + if (holder) {
> > + /* Add holder device path to the list */
> > + iothread_ref(iothread, holder);
> > + }
> >
> > return iothread->ctx;
> > }
> >
> > +void iothread_put_aio_context(IOThread *iothread, const char *holder)
> > +{
> > + /* Delete holder device path from the list */
> > + iothread_unref(iothread, holder);
> > +}
> > +
> > static int query_one_iothread(Object *object, void *opaque)
> > {
> > IOThreadInfoList ***tail = opaque;
> > --
> > 2.49.0
> >