On Mon, Oct 14, 2024 at 3:45 PM Roman Penyaev <r.peni...@gmail.com> wrote:

> Frontends can be attached and detached during run-time (although detach
> is not implemented, but will follow). Counter variable of muxes is not
> enough for proper attach/detach management, so this patch implements
> bitset: if bit is set for the `mux_bitset` variable, then frontend
> device can be found in the `backend` array (yes, huge confusion with
> backend and frontends names).
>
> Signed-off-by: Roman Penyaev <r.peni...@gmail.com>
> Cc: "Marc-André Lureau" <marcandre.lur...@redhat.com>
> Cc: qemu-devel@nongnu.org
> ---
>  chardev/char-mux.c         | 41 +++++++++++++++++++++++++-------------
>  chardev/char.c             |  2 +-
>  chardev/chardev-internal.h |  2 +-
>  3 files changed, 29 insertions(+), 16 deletions(-)
>
> diff --git a/chardev/char-mux.c b/chardev/char-mux.c
> index 9294f955462e..9c3cacb2fecd 100644
> --- a/chardev/char-mux.c
> +++ b/chardev/char-mux.c
> @@ -26,6 +26,7 @@
>  #include "qapi/error.h"
>  #include "qemu/module.h"
>  #include "qemu/option.h"
> +#include "qemu/bitops.h"
>  #include "chardev/char.h"
>  #include "sysemu/block-backend.h"
>  #include "qapi/qapi-commands-control.h"
> @@ -168,12 +169,19 @@ static int mux_proc_byte(Chardev *chr, MuxChardev
> *d, int ch)
>          case 'b':
>              qemu_chr_be_event(chr, CHR_EVENT_BREAK);
>              break;
> -        case 'c':
> -            assert(d->mux_cnt > 0); /* handler registered with first fe */
> +        case 'c': {
> +            unsigned int bit;
> +
> +            /* Handler registered with first fe */
> +            assert(d->mux_bitset != 0);
>              /* Switch to the next registered device */
> -            mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
> +            bit = find_next_bit(&d->mux_bitset, MAX_MUX, d->focus + 1);
> +            if (bit >= MAX_MUX) {
> +                bit = find_next_bit(&d->mux_bitset, MAX_MUX, 0);
> +            }
> +            mux_set_focus(chr, bit);
>              break;
> -        case 't':
> +        } case 't':
>              d->timestamps = !d->timestamps;
>              d->timestamps_start = -1;
>              d->linestart = false;
> @@ -243,15 +250,16 @@ static void mux_chr_read(void *opaque, const uint8_t
> *buf, int size)
>  void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event)
>  {
>      MuxChardev *d = MUX_CHARDEV(chr);
> -    unsigned int i;
> +    int bit;
>
>      if (!muxes_opened) {
>          return;
>      }
>
>      /* Send the event to all registered listeners */
> -    for (i = 0; i < d->mux_cnt; i++) {
> -        mux_chr_send_event(d, i, event);
> +    bit = -1;
> +    while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) <
> MAX_MUX) {
> +        mux_chr_send_event(d, bit, event);
>      }
>  }
>
> @@ -276,10 +284,11 @@ static GSource *mux_chr_add_watch(Chardev *s,
> GIOCondition cond)
>  static void char_mux_finalize(Object *obj)
>  {
>      MuxChardev *d = MUX_CHARDEV(obj);
> -    unsigned int i;
> +    int bit;
>
> -    for (i = 0; i < d->mux_cnt; i++) {
> -        CharBackend *be = d->backends[i];
> +    bit = -1;
> +    while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) <
> MAX_MUX) {
> +        CharBackend *be = d->backends[bit];
>          if (be) {
>              be->chr = NULL;
>          }
> @@ -304,7 +313,10 @@ static void mux_chr_update_read_handlers(Chardev *chr)
>  bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
>                               unsigned int *tag, Error **errp)
>  {
> -    if (d->mux_cnt >= MAX_MUX) {
> +    unsigned int bit;
> +
> +    bit = find_next_zero_bit(&d->mux_bitset, MAX_MUX, 0);
> +    if (bit >= MAX_MUX) {
>          error_setg(errp,
>                     "too many uses of multiplexed chardev '%s'"
>                     " (maximum is " stringify(MAX_MUX) ")",
> @@ -312,8 +324,9 @@ bool mux_chr_attach_frontend(MuxChardev *d,
> CharBackend *b,
>          return false;
>      }
>
> -    d->backends[d->mux_cnt] = b;
> -    *tag = d->mux_cnt++;
> +    d->mux_bitset |= (1 << bit);
> +    d->backends[bit] = b;
> +    *tag = bit;
>
>      return true;
>  }
> @@ -322,7 +335,7 @@ void mux_set_focus(Chardev *chr, unsigned int focus)
>  {
>      MuxChardev *d = MUX_CHARDEV(chr);
>
> -    assert(focus < d->mux_cnt);
> +    assert(find_next_bit(&d->mux_bitset, MAX_MUX, focus) < MAX_MUX);
>

Wouldn't this be more correct?

+    assert(find_next_bit(&d->mux_bitset, MAX_MUX, focus) == focus);


>
>      if (d->focus != -1) {
>          mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
> diff --git a/chardev/char.c b/chardev/char.c
> index f54dc3a86286..a1722aa076d9 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -333,7 +333,7 @@ static bool qemu_chr_is_busy(Chardev *s)
>  {
>      if (CHARDEV_IS_MUX(s)) {
>          MuxChardev *d = MUX_CHARDEV(s);
> -        return d->mux_cnt > 0;
> +        return d->mux_bitset != 0;
>      } else {
>          return s->be != NULL;
>      }
> diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
> index 8126ce180690..b89aada5413b 100644
> --- a/chardev/chardev-internal.h
> +++ b/chardev/chardev-internal.h
> @@ -37,8 +37,8 @@ struct MuxChardev {
>      Chardev parent;
>      CharBackend *backends[MAX_MUX];
>      CharBackend chr;
> +    unsigned long mux_bitset;
>      int focus;
> -    unsigned int mux_cnt;
>      bool term_got_escape;
>      /* Intermediate input buffer catches escape sequences even if the
>         currently active device is not accepting any input - but only
> until it
> --
> 2.34.1
>
>
>

-- 
Marc-André Lureau

Reply via email to