diff mbox series

[6/8] chardev/mux: switch mux frontends management to bitset

Message ID 20241014114135.389766-7-r.peniaev@gmail.com
State New
Headers show
Series chardev/mux: implement frontend detach | expand

Commit Message

Roman Penyaev Oct. 14, 2024, 11:41 a.m. UTC
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.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@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(-)

Comments

Marc-André Lureau Oct. 14, 2024, 1:20 p.m. UTC | #1
On Mon, Oct 14, 2024 at 3:45 PM Roman Penyaev <r.peniaev@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.peniaev@gmail.com>
> Cc: "Marc-André Lureau" <marcandre.lureau@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
>
>
>
Roman Penyaev Oct. 14, 2024, 1:56 p.m. UTC | #2
On Mon, Oct 14, 2024 at 3:20 PM Marc-André Lureau
<marcandre.lureau@gmail.com> wrote:
>
>
>
> On Mon, Oct 14, 2024 at 3:45 PM Roman Penyaev <r.peniaev@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.peniaev@gmail.com>
>> Cc: "Marc-André Lureau" <marcandre.lureau@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);
>

Yes, makes sense. Thanks.

Do you want the whole patchset to be resend,
or only changed patches with "v2" prefix in subject?

--
Roman
Marc-André Lureau Oct. 14, 2024, 2:02 p.m. UTC | #3
On Mon, Oct 14, 2024 at 5:58 PM Roman Penyaev <r.peniaev@gmail.com> wrote:

> On Mon, Oct 14, 2024 at 3:20 PM Marc-André Lureau
> <marcandre.lureau@gmail.com> wrote:
> >
> >
> >
> > On Mon, Oct 14, 2024 at 3:45 PM Roman Penyaev <r.peniaev@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.peniaev@gmail.com>
> >> Cc: "Marc-André Lureau" <marcandre.lureau@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);
> >
>
> Yes, makes sense. Thanks.
>
> Do you want the whole patchset to be resend,
> or only changed patches with "v2" prefix in subject?
>

Yes, please send a v2 with the change and r-b. For the other series, use
Based-on tag as necessary (
https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg01288.html)

thanks
diff mbox series

Patch

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);
 
     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