chardev patch queue
-----BEGIN PGP SIGNATURE----- iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmcOLLEcHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5eTaD/0Strje27bLtepVKLQU ZbD9X89G8lI2l87j9odwLjWcUEFCTVBhVgSCzrRdllWTlJoc5NVSUPQT9KcuWRpx MOjaiR+BO/QnflAKN0GfxCQAnPfYb/29rIe2Xr8co8byVUuE32GPcAy+0xoScOHD tpFbZegESsJ8MJN/pmYX83rt82mcNnCxIJxSxm7f4W8+3pdmFPsGQ8Ph+oVnz2n0 Ag32e9rPUON6yeIZDyyc9Bn+JDxH+DsB8kK5N+KwoKvFIH3Knu725m8skwZvXjl0 HmscpivJ4JS2N//Y0s891PaBFBzQOjWgv/EtBdW/LQZTcQdjaV4ZF1mUuom/oVPJ ydtoJz44dkSC/dOf4J6uwWTk7PNCqlqQfHRuZqosedIAw9MFvBSq5NhfPTut2qKr AWPu4r82zM18a/GEjRLPXCnF2APPGa56WhSxn8jGe+FIxcCADDCA9TAzSJLPMHJ8 5moXFmPXjYNrT/Wj4jsso73GCCGNPSNcJa+6/avn7SW8SjJGtpj3f7Qj5Aou5i+j zsFyzFlAKnGQMBi1Qv4kfd4H87hqGvVahT9+uG/pKfvNQw1VB4dKMWSNs1Utiuim sydt2VBwx6B923/6bmZ5HTbO5S9Hfep9jgwemPONNiIi5UeUCv6wTs0f8aallrv0 idOZFmMK5JNn2NybEgALL1x6lg== =+W1p -----END PGP SIGNATURE----- Merge tag 'chr-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging chardev patch queue # -----BEGIN PGP SIGNATURE----- # # iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmcOLLEcHG1hcmNhbmRy # ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5eTaD/0Strje27bLtepVKLQU # ZbD9X89G8lI2l87j9odwLjWcUEFCTVBhVgSCzrRdllWTlJoc5NVSUPQT9KcuWRpx # MOjaiR+BO/QnflAKN0GfxCQAnPfYb/29rIe2Xr8co8byVUuE32GPcAy+0xoScOHD # tpFbZegESsJ8MJN/pmYX83rt82mcNnCxIJxSxm7f4W8+3pdmFPsGQ8Ph+oVnz2n0 # Ag32e9rPUON6yeIZDyyc9Bn+JDxH+DsB8kK5N+KwoKvFIH3Knu725m8skwZvXjl0 # HmscpivJ4JS2N//Y0s891PaBFBzQOjWgv/EtBdW/LQZTcQdjaV4ZF1mUuom/oVPJ # ydtoJz44dkSC/dOf4J6uwWTk7PNCqlqQfHRuZqosedIAw9MFvBSq5NhfPTut2qKr # AWPu4r82zM18a/GEjRLPXCnF2APPGa56WhSxn8jGe+FIxcCADDCA9TAzSJLPMHJ8 # 5moXFmPXjYNrT/Wj4jsso73GCCGNPSNcJa+6/avn7SW8SjJGtpj3f7Qj5Aou5i+j # zsFyzFlAKnGQMBi1Qv4kfd4H87hqGvVahT9+uG/pKfvNQw1VB4dKMWSNs1Utiuim # sydt2VBwx6B923/6bmZ5HTbO5S9Hfep9jgwemPONNiIi5UeUCv6wTs0f8aallrv0 # idOZFmMK5JNn2NybEgALL1x6lg== # =+W1p # -----END PGP SIGNATURE----- # gpg: Signature made Tue 15 Oct 2024 09:49:53 BST # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * tag 'chr-pull-request' of https://gitlab.com/marcandre.lureau/qemu: tests/unit/test-char: implement a few mux remove test cases chardev/mux: implement detach of frontends from mux chardev/mux: switch mux frontends management to bitset chardev/mux: introduce `mux_chr_attach_frontend() call chardev/mux: convert size members to unsigned int chardev/mux: use bool type for `linestart` and `term_got_escape` chardev/chardev-internal: remove unused `max_size` struct member chardev/char: fix qemu_chr_is_busy() check Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c155d13167
@ -191,22 +191,15 @@ 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)) {
|
||||
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;
|
||||
@ -232,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);
|
||||
|
@ -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"
|
||||
@ -73,11 +74,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,7 +125,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];
|
||||
|
||||
@ -145,7 +147,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;
|
||||
}
|
||||
@ -167,19 +169,26 @@ 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 = 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;
|
||||
@ -242,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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,14 +285,15 @@ static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
|
||||
static void char_mux_finalize(Object *obj)
|
||||
{
|
||||
MuxChardev *d = MUX_CHARDEV(obj);
|
||||
int i;
|
||||
int bit;
|
||||
|
||||
for (i = 0; i < d->mux_cnt; i++) {
|
||||
CharBackend *be = d->backends[i];
|
||||
if (be) {
|
||||
be->chr = NULL;
|
||||
}
|
||||
bit = -1;
|
||||
while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
|
||||
CharBackend *be = d->backends[bit];
|
||||
be->chr = NULL;
|
||||
d->backends[bit] = NULL;
|
||||
}
|
||||
d->mux_bitset = 0;
|
||||
qemu_chr_fe_deinit(&d->chr, false);
|
||||
}
|
||||
|
||||
@ -300,12 +311,47 @@ static void mux_chr_update_read_handlers(Chardev *chr)
|
||||
chr->gcontext, true, false);
|
||||
}
|
||||
|
||||
void mux_set_focus(Chardev *chr, int focus)
|
||||
bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
|
||||
unsigned int *tag, Error **errp)
|
||||
{
|
||||
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) ")",
|
||||
d->parent.label);
|
||||
return false;
|
||||
}
|
||||
|
||||
d->mux_bitset |= (1 << bit);
|
||||
d->backends[bit] = b;
|
||||
*tag = bit;
|
||||
|
||||
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);
|
||||
|
||||
assert(focus >= 0);
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -37,20 +37,19 @@ struct MuxChardev {
|
||||
Chardev parent;
|
||||
CharBackend *backends[MAX_MUX];
|
||||
CharBackend chr;
|
||||
unsigned long mux_bitset;
|
||||
int focus;
|
||||
int mux_cnt;
|
||||
int term_got_escape;
|
||||
int max_size;
|
||||
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. */
|
||||
int linestart;
|
||||
bool linestart;
|
||||
int64_t timestamps_start;
|
||||
};
|
||||
typedef struct MuxChardev MuxChardev;
|
||||
@ -60,7 +59,10 @@ 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);
|
||||
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);
|
||||
|
||||
Object *get_chardevs_root(void);
|
||||
|
@ -20,7 +20,7 @@ struct CharBackend {
|
||||
IOReadHandler *chr_read;
|
||||
BackendChangeHandler *chr_be_change;
|
||||
void *opaque;
|
||||
int tag;
|
||||
unsigned int tag;
|
||||
bool fe_is_open;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
qmp_chardev_remove("mux-label", &error);
|
||||
g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy");
|
||||
error_free(error);
|
||||
|
||||
qemu_chr_fe_deinit(&chr_be2, false);
|
||||
qmp_chardev_remove("mux-label", &error_abort);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user