Zhang Chen <[email protected]> writes:

> Monitors that require an IOThread share the internal mon_iothread.
> Account for each monitor explicitly in IOThread holder tracking, using
> the monitor's canonical QOM path to distinguish holders.
>
> Acquire the shared monitor IOThread AioContext once and store the
> IOThread and canonical QOM path so the holder can be released after the
> monitor has been removed from the QOM tree. Use the stored IOThread for
> per-monitor checks and accesses after initialization, and reuse the
> stored context for later operations.
>
> Release the holder from monitor_finalize(), after resources associated
> with the AioContext have been destroyed. This pairs the reference taken
> in complete() with instance finalization and keeps the IOThread alive
> throughout monitor teardown.
>
> The internal mon_iothread remains hidden from query-iothreads, as before.
> Management applications therefore cannot use it to determine which
> monitors are using the IOThread. Nevertheless, track the monitor
> holders so that they follow the same explicit holder and
> IOThread reference lifecycle as other AioContext users.
>
> Signed-off-by: Zhang Chen <[email protected]>
> ---
>  monitor/monitor-internal.h |  7 +++++--
>  monitor/monitor.c          | 36 ++++++++++++++++++++++++++----------
>  monitor/qmp.c              | 14 +++++++-------
>  3 files changed, 38 insertions(+), 19 deletions(-)
>
> diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
> index 822a66d06d..020afdaebf 100644
> --- a/monitor/monitor-internal.h
> +++ b/monitor/monitor-internal.h
> @@ -77,6 +77,11 @@ struct Monitor {
>      GString *outbuf;
>      guint out_watch;
>      int mux_out;
> +
> +    /* iothread context and holder identity */
> +    IOThread *iothread;
> +    char *iothread_qom_path;
> +    AioContext *ctx;
>  };
>  
>  struct MonitorQMPClass {
> @@ -109,14 +114,12 @@ struct MonitorQMP {
>  };
>  
>  typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
> -extern IOThread *mon_iothread;
>  extern Coroutine *qmp_dispatcher_co;
>  extern bool qmp_dispatcher_co_shutdown;
>  extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
>  extern QemuMutex monitor_lock;
>  extern MonitorList mon_list;
>  
> -bool monitor_requires_iothread(const Monitor *mon);
>  int monitor_can_read(void *opaque);
>  void monitor_cancel_out_watch(Monitor *mon);
>  void monitor_list_append(Monitor *mon);
> diff --git a/monitor/monitor.c b/monitor/monitor.c
> index 2654b81890..a80d8dbf45 100644
> --- a/monitor/monitor.c
> +++ b/monitor/monitor.c
> @@ -55,7 +55,7 @@ typedef struct {
>  } MonitorQAPIEventConf;
>  
>  /* Shared monitor I/O thread */
> -IOThread *mon_iothread;
> +static IOThread *mon_iothread;
>  
>  /* Coroutine to dispatch the requests received from I/O thread */
>  Coroutine *qmp_dispatcher_co;
> @@ -93,6 +93,16 @@ static void monitor_finalize(Object *obj)
>      qemu_chr_fe_deinit(&mon->chr, false);
>      g_string_free(mon->outbuf, true);
>      qemu_mutex_destroy(&mon->mon_lock);
> +
> +    if (mon->iothread) {
> +        const IOThreadHolder io_holder = {
> +            .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
> +            .u.qom_object.qom_path = mon->iothread_qom_path,
> +        };
> +
> +        iothread_unref_and_put_aio_context(mon->iothread, &io_holder);
> +    }
> +    g_free(mon->iothread_qom_path);
>  }
>  
>  static char *monitor_get_chardev_id(Object *obj, Error **errp)
> @@ -164,7 +174,7 @@ Monitor *monitor_set_cur(Coroutine *co, Monitor *mon)
>      return old_monitor;
>  }
>  
> -bool monitor_requires_iothread(const Monitor *mon)
> +static bool monitor_requires_iothread(const Monitor *mon)
>  {
>      MonitorClass *cls = MONITOR_GET_CLASS(mon);
>      return cls->requires_iothread && cls->requires_iothread(mon);
> @@ -188,8 +198,8 @@ void monitor_cancel_out_watch(Monitor *mon)
>          GMainContext *ctx = NULL;
>          GSource *src;
>  
> -        if (monitor_requires_iothread(mon)) {
> -            ctx = iothread_get_g_main_context(mon_iothread);
> +        if (mon->iothread) {
> +            ctx = iothread_get_g_main_context(mon->iothread);
>          }
>          src = g_main_context_find_source_by_id(ctx, mon->out_watch);
>          if (!src && ctx) {
> @@ -516,12 +526,12 @@ void monitor_suspend(Monitor *mon)
>  {
>      qatomic_inc(&mon->suspend_cnt);
>  
> -    if (monitor_requires_iothread(mon)) {
> +    if (mon->iothread) {
>          /*
>           * Kick I/O thread to make sure this takes effect.  It'll be
>           * evaluated again in prepare() of the watch object.
>           */
> -        aio_notify(iothread_get_aio_context(mon_iothread));
> +        aio_notify(mon->ctx);
>      }
>  
>      trace_monitor_suspend(mon, 1);
> @@ -661,7 +671,6 @@ char *monitor_compat_id(void)
>  static void monitor_complete(UserCreatable *uc, Error **errp)
>  {
>      Monitor *mon = MONITOR(uc);
> -    AioContext *ctx;
>  
>      if (mon->chardev_id) {
>          Chardev *chr = qemu_chr_find(mon->chardev_id);
> @@ -680,11 +689,18 @@ static void monitor_complete(UserCreatable *uc, Error 
> **errp)
>              mon_iothread = iothread_create("mon_iothread", &error_abort);
>          }
>  
> -        ctx = iothread_get_aio_context(mon_iothread);
> +        mon->iothread = mon_iothread;
> +        mon->iothread_qom_path = object_get_canonical_path(OBJECT(mon));

Hmm, this is the monitor's QOM path, not the I/O threads.  Let's rename
Monitor member iothread_qom_path to monitor_qom_path or just qom_path.

> +        const IOThreadHolder io_holder = {
> +            .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
> +            .u.qom_object.qom_path = mon->iothread_qom_path,
> +        };
> +
> +        mon->ctx = iothread_ref_and_get_aio_context(mon->iothread, 
> &io_holder);
>      } else {
> -        ctx = qemu_get_aio_context();
> +        mon->ctx = qemu_get_aio_context();
>      }
> -    mon->accept_input_bh = aio_bh_new(ctx, monitor_accept_input, mon);
> +    mon->accept_input_bh = aio_bh_new(mon->ctx, monitor_accept_input, mon);
>  }
>  
>  int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
> diff --git a/monitor/qmp.c b/monitor/qmp.c
> index aec0315775..e235302fb3 100644
> --- a/monitor/qmp.c
> +++ b/monitor/qmp.c
> @@ -187,7 +187,7 @@ static void monitor_qmp_caps_reset(MonitorQMP *mon)
>      memset(mon->capab_offered, 0, sizeof(mon->capab_offered));
>      memset(mon->capab, 0, sizeof(mon->capab));
>      mon->capab_offered[QMP_CAPABILITY_OOB] =
> -        monitor_requires_iothread(MONITOR(mon));
> +        MONITOR(mon)->iothread != NULL;
>  }
>  
>  static void qmp_request_free(QMPRequest *req)
> @@ -678,8 +678,8 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
>      MonitorQMP *mon = opaque;
>      GMainContext *context;
>  
> -    assert(monitor_requires_iothread(MONITOR(mon)));
> -    context = iothread_get_g_main_context(mon_iothread);
> +    assert(MONITOR(mon)->iothread);
> +    context = iothread_get_g_main_context(MONITOR(mon)->iothread);
>      assert(context);
>      qemu_chr_fe_set_handlers(&mon->parent_obj.chr, monitor_can_read,
>                               monitor_qmp_read, monitor_qmp_event,
> @@ -717,7 +717,7 @@ static void monitor_qmp_complete(UserCreatable *uc, Error 
> **errp)
>  
>      qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
>  
> -    if (monitor_requires_iothread(MONITOR(mon))) {
> +    if (MONITOR(mon)->iothread) {
>          /*
>           * Make sure the old iowatch is gone.  It's possible when
>           * e.g. the chardev is in client mode, with wait=on.
> @@ -734,7 +734,7 @@ static void monitor_qmp_complete(UserCreatable *uc, Error 
> **errp)
>           * thread.  Schedule a bottom half.
>           */
>          mon->setup_pending = true;
> -        aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread),
> +        aio_bh_schedule_oneshot(MONITOR(mon)->ctx,
>                                  monitor_qmp_setup_handlers_bh, mon);
>          /* The bottom half will add @mon to @mon_list */
>      } else {
> @@ -788,8 +788,8 @@ static bool monitor_qmp_prepare_delete(UserCreatable *uc, 
> Error **errp)
>      }
>  
>      /* Synchronize with in-flight iothread callbacks. */
> -    if (monitor_requires_iothread(mon)) {
> -        aio_wait_bh_oneshot(iothread_get_aio_context(mon_iothread),
> +    if (mon->iothread) {
> +        aio_wait_bh_oneshot(mon->ctx,
>                              monitor_qmp_iothread_quiesce, NULL);
>      }

With the rename
Reviewed-by: Markus Armbruster <[email protected]>


Reply via email to