chardev/mux: switch mux frontends management to bitset

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
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20241014152408.427700-7-r.peniaev@gmail.com>
This commit is contained in:
Roman Penyaev 2024-10-14 17:24:06 +02:00 committed by Marc-André Lureau
parent 709a4cabfb
commit 005b6d511f
3 changed files with 30 additions and 16 deletions

View file

@ -26,6 +26,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/bitops.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-control.h"
@ -168,12 +169,19 @@ static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
case 'b': case 'b':
qemu_chr_be_event(chr, CHR_EVENT_BREAK); qemu_chr_be_event(chr, CHR_EVENT_BREAK);
break; break;
case 'c': case 'c': {
assert(d->mux_cnt > 0); /* handler registered with first fe */ unsigned int bit;
/* Handler registered with first fe */
assert(d->mux_bitset != 0);
/* Switch to the next registered device */ /* 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; break;
case 't': } case 't':
d->timestamps = !d->timestamps; d->timestamps = !d->timestamps;
d->timestamps_start = -1; d->timestamps_start = -1;
d->linestart = false; d->linestart = false;
@ -243,15 +251,16 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event) void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event)
{ {
MuxChardev *d = MUX_CHARDEV(chr); MuxChardev *d = MUX_CHARDEV(chr);
unsigned int i; int bit;
if (!muxes_opened) { if (!muxes_opened) {
return; return;
} }
/* Send the event to all registered listeners */ /* Send the event to all registered listeners */
for (i = 0; i < d->mux_cnt; i++) { bit = -1;
mux_chr_send_event(d, i, event); while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
mux_chr_send_event(d, bit, event);
} }
} }
@ -276,10 +285,11 @@ static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
static void char_mux_finalize(Object *obj) static void char_mux_finalize(Object *obj)
{ {
MuxChardev *d = MUX_CHARDEV(obj); MuxChardev *d = MUX_CHARDEV(obj);
unsigned int i; int bit;
for (i = 0; i < d->mux_cnt; i++) { bit = -1;
CharBackend *be = d->backends[i]; while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
CharBackend *be = d->backends[bit];
if (be) { if (be) {
be->chr = NULL; be->chr = NULL;
} }
@ -304,7 +314,10 @@ static void mux_chr_update_read_handlers(Chardev *chr)
bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b, bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
unsigned int *tag, Error **errp) 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, error_setg(errp,
"too many uses of multiplexed chardev '%s'" "too many uses of multiplexed chardev '%s'"
" (maximum is " stringify(MAX_MUX) ")", " (maximum is " stringify(MAX_MUX) ")",
@ -312,8 +325,9 @@ bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
return false; return false;
} }
d->backends[d->mux_cnt] = b; d->mux_bitset |= (1 << bit);
*tag = d->mux_cnt++; d->backends[bit] = b;
*tag = bit;
return true; return true;
} }
@ -322,7 +336,7 @@ void mux_set_focus(Chardev *chr, unsigned int focus)
{ {
MuxChardev *d = MUX_CHARDEV(chr); MuxChardev *d = MUX_CHARDEV(chr);
assert(focus < d->mux_cnt); assert(find_next_bit(&d->mux_bitset, MAX_MUX, focus) == focus);
if (d->focus != -1) { if (d->focus != -1) {
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);

View file

@ -333,7 +333,7 @@ static bool qemu_chr_is_busy(Chardev *s)
{ {
if (CHARDEV_IS_MUX(s)) { if (CHARDEV_IS_MUX(s)) {
MuxChardev *d = MUX_CHARDEV(s); MuxChardev *d = MUX_CHARDEV(s);
return d->mux_cnt > 0; return d->mux_bitset != 0;
} else { } else {
return s->be != NULL; return s->be != NULL;
} }

View file

@ -37,8 +37,8 @@ struct MuxChardev {
Chardev parent; Chardev parent;
CharBackend *backends[MAX_MUX]; CharBackend *backends[MAX_MUX];
CharBackend chr; CharBackend chr;
unsigned long mux_bitset;
int focus; int focus;
unsigned int mux_cnt;
bool term_got_escape; bool term_got_escape;
/* Intermediate input buffer catches escape sequences even if the /* Intermediate input buffer catches escape sequences even if the
currently active device is not accepting any input - but only until it currently active device is not accepting any input - but only until it