* [PATCH v2 1/8] chardev/char: fix qemu_chr_is_busy() check
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 2/8] chardev/chardev-internal: remove unused `max_size` struct member Roman Penyaev
` (6 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
`mux_cnt` struct member never goes negative or decrements,
so mux chardev can be !busy only when there are no
frontends attached. This patch fixes the always-true
check.
Fixes: a4afa548fc6d ("char: move front end handlers in CharBackend")
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
---
chardev/char.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/chardev/char.c b/chardev/char.c
index c0cc52824b48..f54dc3a86286 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_cnt > 0;
} else {
return s->be != NULL;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 2/8] chardev/chardev-internal: remove unused `max_size` struct member
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 1/8] chardev/char: fix qemu_chr_is_busy() check Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-22 5:21 ` CLEMENT MATHIEU--DRIF
2024-10-14 15:24 ` [PATCH v2 3/8] chardev/mux: use bool type for `linestart` and `term_got_escape` Roman Penyaev
` (5 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
Clean up forgotten leftovers.
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
---
chardev/chardev-internal.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
index 4e03af31476c..c3024b51fdda 100644
--- a/chardev/chardev-internal.h
+++ b/chardev/chardev-internal.h
@@ -40,7 +40,6 @@ struct MuxChardev {
int focus;
int mux_cnt;
int term_got_escape;
- int max_size;
/* Intermediate input buffer catches escape sequences even if the
currently active device is not accepting any input - but only until it
is full as well. */
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/8] chardev/chardev-internal: remove unused `max_size` struct member
2024-10-14 15:24 ` [PATCH v2 2/8] chardev/chardev-internal: remove unused `max_size` struct member Roman Penyaev
@ 2024-10-22 5:21 ` CLEMENT MATHIEU--DRIF
0 siblings, 0 replies; 15+ messages in thread
From: CLEMENT MATHIEU--DRIF @ 2024-10-22 5:21 UTC (permalink / raw)
To: Roman Penyaev; +Cc: Marc-André Lureau, qemu-devel@nongnu.org
Reviewed-by: Clément Mathieu--Drif <clement.mathieu--drif@eviden.com>
On 14/10/2024 17:24, Roman Penyaev wrote:
> Caution: External email. Do not open attachments or click links, unless this email comes from a known sender and you know the content is safe.
>
>
> Clean up forgotten leftovers.
>
> Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
> Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
> Cc: qemu-devel@nongnu.org
> ---
> chardev/chardev-internal.h | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
> index 4e03af31476c..c3024b51fdda 100644
> --- a/chardev/chardev-internal.h
> +++ b/chardev/chardev-internal.h
> @@ -40,7 +40,6 @@ struct MuxChardev {
> int focus;
> int mux_cnt;
> int term_got_escape;
> - int max_size;
> /* Intermediate input buffer catches escape sequences even if the
> currently active device is not accepting any input - but only until it
> is full as well. */
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 3/8] chardev/mux: use bool type for `linestart` and `term_got_escape`
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 1/8] chardev/char: fix qemu_chr_is_busy() check Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 2/8] chardev/chardev-internal: remove unused `max_size` struct member Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-22 5:21 ` CLEMENT MATHIEU--DRIF
2024-10-14 15:24 ` [PATCH v2 4/8] chardev/mux: convert size members to unsigned int Roman Penyaev
` (4 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
Those are boolean variables, not signed integers.
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 | 10 +++++-----
chardev/chardev-internal.h | 4 ++--
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index ee2d47b20d9b..728596c6f346 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -73,11 +73,11 @@ static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&d->chr,
(uint8_t *)buf1, strlen(buf1));
- d->linestart = 0;
+ d->linestart = false;
}
ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
if (buf[i] == '\n') {
- d->linestart = 1;
+ d->linestart = true;
}
}
}
@@ -145,7 +145,7 @@ static void mux_chr_be_event(Chardev *chr, QEMUChrEvent event)
static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
{
if (d->term_got_escape) {
- d->term_got_escape = 0;
+ d->term_got_escape = false;
if (ch == term_escape_char) {
goto send_char;
}
@@ -175,11 +175,11 @@ static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
case 't':
d->timestamps = !d->timestamps;
d->timestamps_start = -1;
- d->linestart = 0;
+ d->linestart = false;
break;
}
} else if (ch == term_escape_char) {
- d->term_got_escape = 1;
+ d->term_got_escape = true;
} else {
send_char:
return 1;
diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
index c3024b51fdda..975c16de803e 100644
--- a/chardev/chardev-internal.h
+++ b/chardev/chardev-internal.h
@@ -39,7 +39,7 @@ struct MuxChardev {
CharBackend chr;
int focus;
int mux_cnt;
- int term_got_escape;
+ 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
is full as well. */
@@ -49,7 +49,7 @@ struct MuxChardev {
int timestamps;
/* Protected by the Chardev chr_write_lock. */
- int linestart;
+ bool linestart;
int64_t timestamps_start;
};
typedef struct MuxChardev MuxChardev;
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/8] chardev/mux: use bool type for `linestart` and `term_got_escape`
2024-10-14 15:24 ` [PATCH v2 3/8] chardev/mux: use bool type for `linestart` and `term_got_escape` Roman Penyaev
@ 2024-10-22 5:21 ` CLEMENT MATHIEU--DRIF
0 siblings, 0 replies; 15+ messages in thread
From: CLEMENT MATHIEU--DRIF @ 2024-10-22 5:21 UTC (permalink / raw)
To: Roman Penyaev; +Cc: Marc-André Lureau, qemu-devel@nongnu.org
Reviewed-by: Clément Mathieu--Drif <clement.mathieu--drif@eviden.com>
On 14/10/2024 17:24, Roman Penyaev wrote:
> Caution: External email. Do not open attachments or click links, unless this email comes from a known sender and you know the content is safe.
>
>
> Those are boolean variables, not signed integers.
>
> 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 | 10 +++++-----
> chardev/chardev-internal.h | 4 ++--
> 2 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/chardev/char-mux.c b/chardev/char-mux.c
> index ee2d47b20d9b..728596c6f346 100644
> --- a/chardev/char-mux.c
> +++ b/chardev/char-mux.c
> @@ -73,11 +73,11 @@ static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
> * qemu_chr_fe_write and background I/O callbacks */
> qemu_chr_fe_write_all(&d->chr,
> (uint8_t *)buf1, strlen(buf1));
> - d->linestart = 0;
> + d->linestart = false;
> }
> ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
> if (buf[i] == '\n') {
> - d->linestart = 1;
> + d->linestart = true;
> }
> }
> }
> @@ -145,7 +145,7 @@ static void mux_chr_be_event(Chardev *chr, QEMUChrEvent event)
> static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
> {
> if (d->term_got_escape) {
> - d->term_got_escape = 0;
> + d->term_got_escape = false;
> if (ch == term_escape_char) {
> goto send_char;
> }
> @@ -175,11 +175,11 @@ static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
> case 't':
> d->timestamps = !d->timestamps;
> d->timestamps_start = -1;
> - d->linestart = 0;
> + d->linestart = false;
> break;
> }
> } else if (ch == term_escape_char) {
> - d->term_got_escape = 1;
> + d->term_got_escape = true;
> } else {
> send_char:
> return 1;
> diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
> index c3024b51fdda..975c16de803e 100644
> --- a/chardev/chardev-internal.h
> +++ b/chardev/chardev-internal.h
> @@ -39,7 +39,7 @@ struct MuxChardev {
> CharBackend chr;
> int focus;
> int mux_cnt;
> - int term_got_escape;
> + 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
> is full as well. */
> @@ -49,7 +49,7 @@ struct MuxChardev {
> int timestamps;
>
> /* Protected by the Chardev chr_write_lock. */
> - int linestart;
> + bool linestart;
> int64_t timestamps_start;
> };
> typedef struct MuxChardev MuxChardev;
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 4/8] chardev/mux: convert size members to unsigned int
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
` (2 preceding siblings ...)
2024-10-14 15:24 ` [PATCH v2 3/8] chardev/mux: use bool type for `linestart` and `term_got_escape` Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 5/8] chardev/mux: introduce `mux_chr_attach_frontend() call Roman Penyaev
` (3 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
There is no sense to keep `focus`, `mux_cnt`, `prod`, `cons`
and `tag` variables as signed, those represent either size,
either position in array, which both are unsigned.
`focus` member of `MuxChardev` is kept signed, because initially
set to -1.
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
---
chardev/char-fe.c | 2 +-
chardev/char-mux.c | 10 +++++-----
chardev/chardev-internal.h | 8 ++++----
include/chardev/char-fe.h | 2 +-
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index b214ba3802b1..69b47d16bdfa 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -191,7 +191,7 @@ bool qemu_chr_fe_backend_open(CharBackend *be)
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
{
- int tag = 0;
+ unsigned int tag = 0;
if (s) {
if (CHARDEV_IS_MUX(s)) {
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 728596c6f346..b2d7abf2fc01 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -124,7 +124,8 @@ static void mux_print_help(Chardev *chr)
}
}
-static void mux_chr_send_event(MuxChardev *d, int mux_nr, QEMUChrEvent event)
+static void mux_chr_send_event(MuxChardev *d, unsigned int mux_nr,
+ QEMUChrEvent event)
{
CharBackend *be = d->backends[mux_nr];
@@ -242,7 +243,7 @@ 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);
- int i;
+ unsigned int i;
if (!muxes_opened) {
return;
@@ -275,7 +276,7 @@ static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
static void char_mux_finalize(Object *obj)
{
MuxChardev *d = MUX_CHARDEV(obj);
- int i;
+ unsigned int i;
for (i = 0; i < d->mux_cnt; i++) {
CharBackend *be = d->backends[i];
@@ -300,11 +301,10 @@ static void mux_chr_update_read_handlers(Chardev *chr)
chr->gcontext, true, false);
}
-void mux_set_focus(Chardev *chr, int focus)
+void mux_set_focus(Chardev *chr, unsigned int focus)
{
MuxChardev *d = MUX_CHARDEV(chr);
- assert(focus >= 0);
assert(focus < d->mux_cnt);
if (d->focus != -1) {
diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
index 975c16de803e..ab93f6ea1720 100644
--- a/chardev/chardev-internal.h
+++ b/chardev/chardev-internal.h
@@ -38,14 +38,14 @@ struct MuxChardev {
CharBackend *backends[MAX_MUX];
CharBackend chr;
int focus;
- int mux_cnt;
+ 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
is full as well. */
unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
- int prod[MAX_MUX];
- int cons[MAX_MUX];
+ unsigned int prod[MAX_MUX];
+ unsigned int cons[MAX_MUX];
int timestamps;
/* Protected by the Chardev chr_write_lock. */
@@ -59,7 +59,7 @@ DECLARE_INSTANCE_CHECKER(MuxChardev, MUX_CHARDEV,
#define CHARDEV_IS_MUX(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
-void mux_set_focus(Chardev *chr, int focus);
+void mux_set_focus(Chardev *chr, unsigned int focus);
void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event);
Object *get_chardevs_root(void);
diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index 3310449eaf03..8ef05b3dd095 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -20,7 +20,7 @@ struct CharBackend {
IOReadHandler *chr_read;
BackendChangeHandler *chr_be_change;
void *opaque;
- int tag;
+ unsigned int tag;
bool fe_is_open;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 5/8] chardev/mux: introduce `mux_chr_attach_frontend() call
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
` (3 preceding siblings ...)
2024-10-14 15:24 ` [PATCH v2 4/8] chardev/mux: convert size members to unsigned int Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 6/8] chardev/mux: switch mux frontends management to bitset Roman Penyaev
` (2 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
Move away logic which attaches frontend device to a mux
from `char-fe.c` to actual `char-mux.c` implementation
and make it a separate function.
No logic changes are made.
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
---
chardev/char-fe.c | 9 +--------
chardev/char-mux.c | 17 +++++++++++++++++
chardev/chardev-internal.h | 2 ++
3 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index 69b47d16bdfa..3b8771ca2ac4 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -197,16 +197,9 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
if (CHARDEV_IS_MUX(s)) {
MuxChardev *d = MUX_CHARDEV(s);
- if (d->mux_cnt >= MAX_MUX) {
- error_setg(errp,
- "too many uses of multiplexed chardev '%s'"
- " (maximum is " stringify(MAX_MUX) ")",
- s->label);
+ if (!mux_chr_attach_frontend(d, b, &tag, errp)) {
return false;
}
-
- d->backends[d->mux_cnt] = b;
- tag = d->mux_cnt++;
} else if (s->be) {
error_setg(errp, "chardev '%s' is already in use", s->label);
return false;
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index b2d7abf2fc01..9294f955462e 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -301,6 +301,23 @@ static void mux_chr_update_read_handlers(Chardev *chr)
chr->gcontext, true, false);
}
+bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
+ unsigned int *tag, Error **errp)
+{
+ if (d->mux_cnt >= MAX_MUX) {
+ error_setg(errp,
+ "too many uses of multiplexed chardev '%s'"
+ " (maximum is " stringify(MAX_MUX) ")",
+ d->parent.label);
+ return false;
+ }
+
+ d->backends[d->mux_cnt] = b;
+ *tag = d->mux_cnt++;
+
+ return true;
+}
+
void mux_set_focus(Chardev *chr, unsigned int focus)
{
MuxChardev *d = MUX_CHARDEV(chr);
diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
index ab93f6ea1720..8126ce180690 100644
--- a/chardev/chardev-internal.h
+++ b/chardev/chardev-internal.h
@@ -59,6 +59,8 @@ DECLARE_INSTANCE_CHECKER(MuxChardev, MUX_CHARDEV,
#define CHARDEV_IS_MUX(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
+bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
+ unsigned int *tag, Error **errp);
void mux_set_focus(Chardev *chr, unsigned int focus);
void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event);
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 6/8] chardev/mux: switch mux frontends management to bitset
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
` (4 preceding siblings ...)
2024-10-14 15:24 ` [PATCH v2 5/8] chardev/mux: introduce `mux_chr_attach_frontend() call Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 7/8] chardev/mux: implement detach of frontends from mux Roman Penyaev
2024-10-14 15:24 ` [PATCH v2 8/8] tests/unit/test-char: implement a few mux remove test cases Roman Penyaev
7 siblings, 0 replies; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
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 | 42 +++++++++++++++++++++++++-------------
chardev/char.c | 2 +-
chardev/chardev-internal.h | 2 +-
3 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 9294f955462e..4fc619b2da70 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 +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)
{
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 +285,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 +314,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 +325,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 +336,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) == 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
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 7/8] chardev/mux: implement detach of frontends from mux
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
` (5 preceding siblings ...)
2024-10-14 15:24 ` [PATCH v2 6/8] chardev/mux: switch mux frontends management to bitset Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-22 5:20 ` CLEMENT MATHIEU--DRIF
2024-10-14 15:24 ` [PATCH v2 8/8] tests/unit/test-char: implement a few mux remove test cases Roman Penyaev
7 siblings, 1 reply; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
With bitset management now it becomes feasible to implement
the logic of detaching frontends from multiplexer.
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
---
chardev/char-fe.c | 2 +-
chardev/char-mux.c | 21 ++++++++++++++++++---
chardev/chardev-internal.h | 1 +
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index 3b8771ca2ac4..8ac6bebb6f74 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -225,7 +225,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
}
if (CHARDEV_IS_MUX(b->chr)) {
MuxChardev *d = MUX_CHARDEV(b->chr);
- d->backends[b->tag] = NULL;
+ mux_chr_detach_frontend(d, b->tag);
}
if (del) {
Object *obj = OBJECT(b->chr);
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 4fc619b2da70..bda5c45e6058 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -290,10 +290,10 @@ static void char_mux_finalize(Object *obj)
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;
- }
+ be->chr = NULL;
+ d->backends[bit] = NULL;
}
+ d->mux_bitset = 0;
qemu_chr_fe_deinit(&d->chr, false);
}
@@ -332,6 +332,21 @@ bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
return true;
}
+bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag)
+{
+ unsigned int bit;
+
+ bit = find_next_bit(&d->mux_bitset, MAX_MUX, tag);
+ if (bit != tag) {
+ return false;
+ }
+
+ d->mux_bitset &= ~(1 << bit);
+ d->backends[bit] = NULL;
+
+ return true;
+}
+
void mux_set_focus(Chardev *chr, unsigned int focus)
{
MuxChardev *d = MUX_CHARDEV(chr);
diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
index b89aada5413b..853807f3cb88 100644
--- a/chardev/chardev-internal.h
+++ b/chardev/chardev-internal.h
@@ -61,6 +61,7 @@ DECLARE_INSTANCE_CHECKER(MuxChardev, MUX_CHARDEV,
bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
unsigned int *tag, Error **errp);
+bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag);
void mux_set_focus(Chardev *chr, unsigned int focus);
void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event);
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 7/8] chardev/mux: implement detach of frontends from mux
2024-10-14 15:24 ` [PATCH v2 7/8] chardev/mux: implement detach of frontends from mux Roman Penyaev
@ 2024-10-22 5:20 ` CLEMENT MATHIEU--DRIF
2024-11-02 11:19 ` Roman Penyaev
0 siblings, 1 reply; 15+ messages in thread
From: CLEMENT MATHIEU--DRIF @ 2024-10-22 5:20 UTC (permalink / raw)
To: Roman Penyaev; +Cc: Marc-André Lureau, qemu-devel@nongnu.org
On 14/10/2024 17:24, Roman Penyaev wrote:
> Caution: External email. Do not open attachments or click links, unless this email comes from a known sender and you know the content is safe.
>
>
> With bitset management now it becomes feasible to implement
> the logic of detaching frontends from multiplexer.
>
> Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
> Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
> Cc: qemu-devel@nongnu.org
> ---
> chardev/char-fe.c | 2 +-
> chardev/char-mux.c | 21 ++++++++++++++++++---
> chardev/chardev-internal.h | 1 +
> 3 files changed, 20 insertions(+), 4 deletions(-)
>
> diff --git a/chardev/char-fe.c b/chardev/char-fe.c
> index 3b8771ca2ac4..8ac6bebb6f74 100644
> --- a/chardev/char-fe.c
> +++ b/chardev/char-fe.c
> @@ -225,7 +225,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
> }
> if (CHARDEV_IS_MUX(b->chr)) {
> MuxChardev *d = MUX_CHARDEV(b->chr);
> - d->backends[b->tag] = NULL;
> + mux_chr_detach_frontend(d, b->tag);
> }
> if (del) {
> Object *obj = OBJECT(b->chr);
> diff --git a/chardev/char-mux.c b/chardev/char-mux.c
> index 4fc619b2da70..bda5c45e6058 100644
> --- a/chardev/char-mux.c
> +++ b/chardev/char-mux.c
> @@ -290,10 +290,10 @@ static void char_mux_finalize(Object *obj)
> 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;
> - }
> + be->chr = NULL;
> + d->backends[bit] = NULL;
> }
> + d->mux_bitset = 0;
> qemu_chr_fe_deinit(&d->chr, false);
> }
>
> @@ -332,6 +332,21 @@ bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
> return true;
> }
>
> +bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag)
> +{
> + unsigned int bit;
> +
> + bit = find_next_bit(&d->mux_bitset, MAX_MUX, tag);
> + if (bit != tag) {
> + return false;
> + }
> +
> + d->mux_bitset &= ~(1 << bit);
mux_bitset is unsigned long, I think we should use 1ul here even id
MAX_MUX is a low value
> + d->backends[bit] = NULL;
> +
> + return true;
> +}
> +
> void mux_set_focus(Chardev *chr, unsigned int focus)
> {
> MuxChardev *d = MUX_CHARDEV(chr);
> diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
> index b89aada5413b..853807f3cb88 100644
> --- a/chardev/chardev-internal.h
> +++ b/chardev/chardev-internal.h
> @@ -61,6 +61,7 @@ DECLARE_INSTANCE_CHECKER(MuxChardev, MUX_CHARDEV,
>
> bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
> unsigned int *tag, Error **errp);
> +bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag);
> void mux_set_focus(Chardev *chr, unsigned int focus);
> void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event);
>
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 7/8] chardev/mux: implement detach of frontends from mux
2024-10-22 5:20 ` CLEMENT MATHIEU--DRIF
@ 2024-11-02 11:19 ` Roman Penyaev
0 siblings, 0 replies; 15+ messages in thread
From: Roman Penyaev @ 2024-11-02 11:19 UTC (permalink / raw)
To: CLEMENT MATHIEU--DRIF; +Cc: Marc-André Lureau, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 2554 bytes --]
Hi,
On Tue, Oct 22, 2024, 07:21 CLEMENT MATHIEU--DRIF <
clement.mathieu--drif@eviden.com> wrote:
>
>
> On 14/10/2024 17:24, Roman Penyaev wrote:
> > Caution: External email. Do not open attachments or click links, unless
> this email comes from a known sender and you know the content is safe.
> >
> >
> > With bitset management now it becomes feasible to implement
> > the logic of detaching frontends from multiplexer.
> >
> > Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
> > Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
> > Cc: qemu-devel@nongnu.org
> > ---
> > chardev/char-fe.c | 2 +-
> > chardev/char-mux.c | 21 ++++++++++++++++++---
> > chardev/chardev-internal.h | 1 +
> > 3 files changed, 20 insertions(+), 4 deletions(-)
> >
> > diff --git a/chardev/char-fe.c b/chardev/char-fe.c
> > index 3b8771ca2ac4..8ac6bebb6f74 100644
> > --- a/chardev/char-fe.c
> > +++ b/chardev/char-fe.c
> > @@ -225,7 +225,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
> > }
> > if (CHARDEV_IS_MUX(b->chr)) {
> > MuxChardev *d = MUX_CHARDEV(b->chr);
> > - d->backends[b->tag] = NULL;
> > + mux_chr_detach_frontend(d, b->tag);
> > }
> > if (del) {
> > Object *obj = OBJECT(b->chr);
> > diff --git a/chardev/char-mux.c b/chardev/char-mux.c
> > index 4fc619b2da70..bda5c45e6058 100644
> > --- a/chardev/char-mux.c
> > +++ b/chardev/char-mux.c
> > @@ -290,10 +290,10 @@ static void char_mux_finalize(Object *obj)
> > 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;
> > - }
> > + be->chr = NULL;
> > + d->backends[bit] = NULL;
> > }
> > + d->mux_bitset = 0;
> > qemu_chr_fe_deinit(&d->chr, false);
> > }
> >
> > @@ -332,6 +332,21 @@ bool mux_chr_attach_frontend(MuxChardev *d,
> CharBackend *b,
> > return true;
> > }
> >
> > +bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag)
> > +{
> > + unsigned int bit;
> > +
> > + bit = find_next_bit(&d->mux_bitset, MAX_MUX, tag);
> > + if (bit != tag) {
> > + return false;
> > + }
> > +
> > + d->mux_bitset &= ~(1 << bit);
>
> mux_bitset is unsigned long, I think we should use 1ul here even id
> MAX_MUX is a low value
>
Sent a patch on that. Thanks.
--
Roman
[-- Attachment #2: Type: text/html, Size: 3794 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 8/8] tests/unit/test-char: implement a few mux remove test cases
2024-10-14 15:24 [PATCH v2 0/8] chardev/mux: implement frontend detach Roman Penyaev
` (6 preceding siblings ...)
2024-10-14 15:24 ` [PATCH v2 7/8] chardev/mux: implement detach of frontends from mux Roman Penyaev
@ 2024-10-14 15:24 ` Roman Penyaev
2024-10-15 8:50 ` Marc-André Lureau
7 siblings, 1 reply; 15+ messages in thread
From: Roman Penyaev @ 2024-10-14 15:24 UTC (permalink / raw)
Cc: Roman Penyaev, Marc-André Lureau, qemu-devel
This patch tests:
1. feasibility of removing mux which does not have frontends attached
or frontends were prior detached.
2. inability to remove mux which has frontends attached (mux is "busy")
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
---
tests/unit/test-char.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/tests/unit/test-char.c b/tests/unit/test-char.c
index f273ce522612..2837dbb863a8 100644
--- a/tests/unit/test-char.c
+++ b/tests/unit/test-char.c
@@ -1,6 +1,7 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
+#include "qapi/error.h"
#include "qemu/config-file.h"
#include "qemu/module.h"
#include "qemu/option.h"
@@ -184,6 +185,21 @@ static void char_mux_test(void)
char *data;
FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
CharBackend chr_be1, chr_be2;
+ Error *error = NULL;
+
+ /* Create mux and chardev to be immediately removed */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", "128", &error_abort);
+ qemu_opt_set(opts, "mux", "on", &error_abort);
+ chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr);
+ qemu_opts_del(opts);
+
+ /* Remove just created mux and chardev */
+ qmp_chardev_remove("mux-label", &error_abort);
+ qmp_chardev_remove("mux-label-base", &error_abort);
opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
1, &error_abort);
@@ -334,7 +350,13 @@ static void char_mux_test(void)
g_free(data);
qemu_chr_fe_deinit(&chr_be1, false);
- qemu_chr_fe_deinit(&chr_be2, true);
+
+ error = NULL;
+ qmp_chardev_remove("mux-label", &error);
+ g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy");
+
+ qemu_chr_fe_deinit(&chr_be2, false);
+ qmp_chardev_remove("mux-label", &error_abort);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 8/8] tests/unit/test-char: implement a few mux remove test cases
2024-10-14 15:24 ` [PATCH v2 8/8] tests/unit/test-char: implement a few mux remove test cases Roman Penyaev
@ 2024-10-15 8:50 ` Marc-André Lureau
2024-10-15 16:51 ` Roman Penyaev
0 siblings, 1 reply; 15+ messages in thread
From: Marc-André Lureau @ 2024-10-15 8:50 UTC (permalink / raw)
To: Roman Penyaev; +Cc: qemu-devel
Hi
On Mon, Oct 14, 2024 at 7:26 PM Roman Penyaev <r.peniaev@gmail.com> wrote:
>
> This patch tests:
>
> 1. feasibility of removing mux which does not have frontends attached
> or frontends were prior detached.
> 2. inability to remove mux which has frontends attached (mux is "busy")
>
> Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
> Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
> Cc: qemu-devel@nongnu.org
> ---
> tests/unit/test-char.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/tests/unit/test-char.c b/tests/unit/test-char.c
> index f273ce522612..2837dbb863a8 100644
> --- a/tests/unit/test-char.c
> +++ b/tests/unit/test-char.c
> @@ -1,6 +1,7 @@
> #include "qemu/osdep.h"
> #include <glib/gstdio.h>
>
> +#include "qapi/error.h"
> #include "qemu/config-file.h"
> #include "qemu/module.h"
> #include "qemu/option.h"
> @@ -184,6 +185,21 @@ static void char_mux_test(void)
> char *data;
> FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
> CharBackend chr_be1, chr_be2;
> + Error *error = NULL;
> +
> + /* Create mux and chardev to be immediately removed */
> + opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
> + 1, &error_abort);
> + qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
> + qemu_opt_set(opts, "size", "128", &error_abort);
> + qemu_opt_set(opts, "mux", "on", &error_abort);
> + chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
> + g_assert_nonnull(chr);
> + qemu_opts_del(opts);
> +
> + /* Remove just created mux and chardev */
> + qmp_chardev_remove("mux-label", &error_abort);
> + qmp_chardev_remove("mux-label-base", &error_abort);
>
> opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
> 1, &error_abort);
> @@ -334,7 +350,13 @@ static void char_mux_test(void)
> g_free(data);
>
> qemu_chr_fe_deinit(&chr_be1, false);
> - qemu_chr_fe_deinit(&chr_be2, true);
> +
> + error = NULL;
Unnecessary assignment,
> + qmp_chardev_remove("mux-label", &error);
> + g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy");
However, error_free() is missing.
I'll touch on commit
thanks
> +
> + qemu_chr_fe_deinit(&chr_be2, false);
> + qmp_chardev_remove("mux-label", &error_abort);
> }
>
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 8/8] tests/unit/test-char: implement a few mux remove test cases
2024-10-15 8:50 ` Marc-André Lureau
@ 2024-10-15 16:51 ` Roman Penyaev
0 siblings, 0 replies; 15+ messages in thread
From: Roman Penyaev @ 2024-10-15 16:51 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 538 bytes --]
Hi,
On Tue, Oct 15, 2024, 10:50 Marc-André Lureau <marcandre.lureau@redhat.com>
wrote:
[cut]
> qemu_chr_fe_deinit(&chr_be1, false);
> > - qemu_chr_fe_deinit(&chr_be2, true);
> > +
> > + error = NULL;
>
> Unnecessary assignment,
>
> > + qmp_chardev_remove("mux-label", &error);
> > + g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label'
> is busy");
>
> However, error_free() is missing.
> I'll touch on commit
>
> thanks
>
My bad, thanks for taking care of this.
--
Roman
[-- Attachment #2: Type: text/html, Size: 1176 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread