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);
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
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
>
>
>
--
Marc-André Lureau
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
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
--
Marc-André Lureau
© 2016 - 2026 Red Hat, Inc.