chardev: introduce 'reconnect-ms' and deprecate 'reconnect'

chardev: add path option for pty backend
 -----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmcGQTYcHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5crYEACdw2EjdHm+OSkC2cUt
 p9x0spZ8xkUJpU7f7Xc+9fIYHTqqmtgKhbC2/iSaeeL8aSN5LugOAP7u0ya9gXo2
 M1pXPx4WYwy7yftmanwVSvD94GPiCT5EN2W3zFMzvkey9b2AdayGyCXaZY2ago4+
 QJq0pPwWu5VFR0b3ocXIJM1WiEzbR6wr+R0xuPGMLAp0uOnNIyE8AD9MhHJ/BROB
 dDCD7xhG6MB1CnRG6+saGV/Aon9mml5i5MmiwmQ6JjC0zZ0w4arkWfjkW5r+yZOc
 BrpC6P+MdwX7t7W//4bszlW0Lv+qw9Q9FBavtLrOSTCy/h+cq5XgNjZnf0j0edNp
 /EGwQ6D7lqbHp0fGX1O+vnWe0IcyGMKWTU05UGpb3TBDzfzlmjNinQxU6LZPfizh
 evRkKELRsy+WTOyJzyeKemw/SdoP8o7RmDF9x3uCP6dF8Q8/UD3CgnwVa8h9L+Jz
 591Ek6srXQhEHkUJdpf48LHvCho4eWkpIy2M7/iurXFZBhpz77A27DCnfBedYg/O
 f67MreVDz3C/RSlsnGj7/c0eKnZHPuNhI4AxCAH01bCy1PEv65LrWUdeAtJRm84X
 upbn9alqP4LCviUBIwjDqSDhb48mYbgmP8sC3oXeyZObSGQUz94oXh1QQapUHSzz
 BCImJN+feMFgLLuEXreJP1N/kQ==
 =musy
 -----END PGP SIGNATURE-----

Merge tag 'chr-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging

chardev: introduce 'reconnect-ms' and deprecate 'reconnect'
chardev: add path option for pty backend

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmcGQTYcHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5crYEACdw2EjdHm+OSkC2cUt
# p9x0spZ8xkUJpU7f7Xc+9fIYHTqqmtgKhbC2/iSaeeL8aSN5LugOAP7u0ya9gXo2
# M1pXPx4WYwy7yftmanwVSvD94GPiCT5EN2W3zFMzvkey9b2AdayGyCXaZY2ago4+
# QJq0pPwWu5VFR0b3ocXIJM1WiEzbR6wr+R0xuPGMLAp0uOnNIyE8AD9MhHJ/BROB
# dDCD7xhG6MB1CnRG6+saGV/Aon9mml5i5MmiwmQ6JjC0zZ0w4arkWfjkW5r+yZOc
# BrpC6P+MdwX7t7W//4bszlW0Lv+qw9Q9FBavtLrOSTCy/h+cq5XgNjZnf0j0edNp
# /EGwQ6D7lqbHp0fGX1O+vnWe0IcyGMKWTU05UGpb3TBDzfzlmjNinQxU6LZPfizh
# evRkKELRsy+WTOyJzyeKemw/SdoP8o7RmDF9x3uCP6dF8Q8/UD3CgnwVa8h9L+Jz
# 591Ek6srXQhEHkUJdpf48LHvCho4eWkpIy2M7/iurXFZBhpz77A27DCnfBedYg/O
# f67MreVDz3C/RSlsnGj7/c0eKnZHPuNhI4AxCAH01bCy1PEv65LrWUdeAtJRm84X
# upbn9alqP4LCviUBIwjDqSDhb48mYbgmP8sC3oXeyZObSGQUz94oXh1QQapUHSzz
# BCImJN+feMFgLLuEXreJP1N/kQ==
# =musy
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 09 Oct 2024 09:39:18 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:
  chardev: add path option for pty backend
  chardev: introduce 'reconnect-ms' and deprecate 'reconnect'

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-10-09 15:06:56 +01:00
commit 838fc0a876
7 changed files with 140 additions and 19 deletions

View File

@ -29,6 +29,7 @@
#include "qemu/sockets.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/qemu-print.h"
#include "chardev/char-io.h"
@ -41,6 +42,7 @@ struct PtyChardev {
int connected;
GSource *timer_src;
char *path;
};
typedef struct PtyChardev PtyChardev;
@ -204,6 +206,12 @@ static void char_pty_finalize(Object *obj)
Chardev *chr = CHARDEV(obj);
PtyChardev *s = PTY_CHARDEV(obj);
/* unlink symlink */
if (s->path) {
unlink(s->path);
g_free(s->path);
}
pty_chr_state(chr, 0);
object_unref(OBJECT(s->ioc));
pty_chr_timer_cancel(s);
@ -330,6 +338,7 @@ static void char_pty_open(Chardev *chr,
int master_fd, slave_fd;
char pty_name[PATH_MAX];
char *name;
char *path = backend->u.pty.data->path;
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
if (master_fd < 0) {
@ -354,12 +363,36 @@ static void char_pty_open(Chardev *chr,
g_free(name);
s->timer_src = NULL;
*be_opened = false;
/* create symbolic link */
if (path) {
int res = symlink(pty_name, path);
if (res != 0) {
error_setg_errno(errp, errno, "Failed to create PTY symlink");
} else {
s->path = g_strdup(path);
}
}
}
static void char_pty_parse(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
{
const char *path = qemu_opt_get(opts, "path");
ChardevPty *pty;
backend->type = CHARDEV_BACKEND_KIND_PTY;
pty = backend->u.pty.data = g_new0(ChardevPty, 1);
qemu_chr_parse_common(opts, qapi_ChardevPty_base(pty));
pty->path = g_strdup(path);
}
static void char_pty_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
cc->parse = char_pty_parse;
cc->open = char_pty_open;
cc->chr_write = char_pty_chr_write;
cc->chr_update_read_handler = pty_chr_update_read_handler;

View File

@ -74,7 +74,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr)
assert(!s->reconnect_timer);
name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
s->reconnect_timer = qemu_chr_timeout_add_ms(chr,
s->reconnect_time * 1000,
s->reconnect_time_ms,
socket_reconnect_timeout,
chr);
g_source_set_name(s->reconnect_timer, name);
@ -481,7 +481,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
if (s->reconnect_time && !s->reconnect_timer) {
if (s->reconnect_time_ms && !s->reconnect_timer) {
qemu_chr_socket_restart_timer(chr);
}
}
@ -1080,9 +1080,9 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
} else {
Error *err = NULL;
if (tcp_chr_connect_client_sync(chr, &err) < 0) {
if (s->reconnect_time) {
if (s->reconnect_time_ms) {
error_free(err);
g_usleep(s->reconnect_time * 1000ULL * 1000ULL);
g_usleep(s->reconnect_time_ms * 1000ULL);
} else {
error_propagate(errp, err);
return -1;
@ -1267,13 +1267,13 @@ skip_listen:
static int qmp_chardev_open_socket_client(Chardev *chr,
int64_t reconnect,
int64_t reconnect_ms,
Error **errp)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
if (reconnect > 0) {
s->reconnect_time = reconnect;
if (reconnect_ms > 0) {
s->reconnect_time_ms = reconnect_ms;
tcp_chr_connect_client_async(chr);
return 0;
} else {
@ -1354,6 +1354,12 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock,
}
}
if (sock->has_reconnect_ms && sock->has_reconnect) {
error_setg(errp,
"'reconnect' and 'reconnect-ms' are mutually exclusive");
return false;
}
return true;
}
@ -1371,7 +1377,7 @@ static void qmp_chardev_open_socket(Chardev *chr,
bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
bool is_waitconnect = sock->has_wait ? sock->wait : false;
bool is_websock = sock->has_websocket ? sock->websocket : false;
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
int64_t reconnect_ms = 0;
SocketAddress *addr;
s->is_listen = is_listen;
@ -1443,7 +1449,13 @@ static void qmp_chardev_open_socket(Chardev *chr,
return;
}
} else {
if (qmp_chardev_open_socket_client(chr, reconnect, errp) < 0) {
if (sock->has_reconnect) {
reconnect_ms = sock->reconnect * 1000ULL;
} else if (sock->has_reconnect_ms) {
reconnect_ms = sock->reconnect_ms;
}
if (qmp_chardev_open_socket_client(chr, reconnect_ms, errp) < 0) {
return;
}
}
@ -1509,6 +1521,9 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock->wait = qemu_opt_get_bool(opts, "wait", true);
sock->has_reconnect = qemu_opt_find(opts, "reconnect");
sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0);
sock->has_reconnect_ms = qemu_opt_find(opts, "reconnect-ms");
sock->reconnect_ms = qemu_opt_get_number(opts, "reconnect-ms", 0);
sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds"));
sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz"));

View File

@ -428,6 +428,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
qemu_opt_set(opts, "path", p, &error_abort);
return opts;
}
if (strstart(filename, "pty:", &p)) {
qemu_opt_set(opts, "backend", "pty", &error_abort);
qemu_opt_set(opts, "path", p, &error_abort);
return opts;
}
if (strstart(filename, "tcp:", &p) ||
strstart(filename, "telnet:", &p) ||
strstart(filename, "tn3270:", &p) ||
@ -888,6 +893,9 @@ QemuOptsList qemu_chardev_opts = {
},{
.name = "reconnect",
.type = QEMU_OPT_NUMBER,
},{
.name = "reconnect-ms",
.type = QEMU_OPT_NUMBER,
},{
.name = "telnet",
.type = QEMU_OPT_BOOL,

View File

@ -394,6 +394,12 @@ Backend ``memory`` (since 9.0)
``memory`` is a deprecated synonym for ``ringbuf``.
``reconnect`` (since 9.2)
^^^^^^^^^^^^^^^^^^^^^^^^^
The ``reconnect`` option only allows specifiying second granularity timeouts,
which is not enough for all types of use cases, use ``reconnect-ms`` instead.
CPU device properties
'''''''''''''''''''''

View File

@ -74,7 +74,7 @@ struct SocketChardev {
bool is_websock;
GSource *reconnect_timer;
int64_t reconnect_time;
int64_t reconnect_time_ms;
bool connect_err_reported;
QIOTask *connect_task;

View File

@ -273,7 +273,19 @@
#
# @reconnect: For a client socket, if a socket is disconnected, then
# attempt a reconnect after the given number of seconds. Setting
# this to zero disables this function. (default: 0) (Since: 2.2)
# this to zero disables this function. The use of this member is
# deprecated, use @reconnect-ms instead. (default: 0) (Since: 2.2)
#
# @reconnect-ms: For a client socket, if a socket is disconnected,
# then attempt a reconnect after the given number of milliseconds.
# Setting this to zero disables this function. This member is
# mutually exclusive with @reconnect.
# (default: 0) (Since: 9.2)
#
# Features:
#
# @deprecated: Member @reconnect is deprecated. Use @reconnect-ms
# instead.
#
# Since: 1.4
##
@ -287,7 +299,8 @@
'*telnet': 'bool',
'*tn3270': 'bool',
'*websocket': 'bool',
'*reconnect': 'int' },
'*reconnect': { 'type': 'int', 'features': [ 'deprecated' ] },
'*reconnect-ms': 'int' },
'base': 'ChardevCommon' }
##
@ -431,6 +444,20 @@
'base': 'ChardevCommon',
'if': 'CONFIG_SPICE_PROTOCOL' }
##
# @ChardevPty:
#
# Configuration info for pty implementation.
#
# @path: optional path to create a symbolic link that points to the
# allocated PTY
#
# Since: 9.2
##
{ 'struct': 'ChardevPty',
'data': { '*path': 'str' },
'base': 'ChardevCommon' }
##
# @ChardevBackendKind:
#
@ -642,6 +669,17 @@
{ 'struct': 'ChardevRingbufWrapper',
'data': { 'data': 'ChardevRingbuf' } }
##
# @ChardevPtyWrapper:
#
# @data: Configuration info for pty chardevs
#
# Since: 9.2
##
{ 'struct': 'ChardevPtyWrapper',
'data': { 'data': 'ChardevPty' } }
##
# @ChardevBackend:
#
@ -662,7 +700,7 @@
'pipe': 'ChardevHostdevWrapper',
'socket': 'ChardevSocketWrapper',
'udp': 'ChardevUdpWrapper',
'pty': 'ChardevCommonWrapper',
'pty': 'ChardevPtyWrapper',
'null': 'ChardevCommonWrapper',
'mux': 'ChardevMuxWrapper',
'msmouse': 'ChardevCommonWrapper',

View File

@ -3712,7 +3712,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev console,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev serial,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
#else
"-chardev pty,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev pty,id=id[,path=path][,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev stdio,id=id[,mux=on|off][,signal=on|off][,logfile=PATH][,logappend=on|off]\n"
#endif
#ifdef CONFIG_BRLAPI
@ -3951,12 +3951,22 @@ The available backends are:
``path`` specifies the name of the serial device to open.
``-chardev pty,id=id``
Create a new pseudo-terminal on the host and connect to it. ``pty``
does not take any options.
``-chardev pty,id=id[,path=path]``
Create a new pseudo-terminal on the host and connect to it.
``pty`` is not available on Windows hosts.
If ``path`` is specified, QEMU will create a symbolic link at
that location which points to the new PTY device.
This avoids having to make QMP or HMP monitor queries to find out
what the new PTY device path is.
Note that while QEMU will remove the symlink when it exits
gracefully, it will not do so in case of crashes or on certain
startup errors. It is recommended that the user checks and removes
the symlink after QEMU terminates to account for this.
``-chardev stdio,id=id[,signal=on|off]``
Connect to standard input and standard output of the QEMU process.
@ -4314,8 +4324,19 @@ SRST
vc:80Cx24C
``pty``
[Linux only] Pseudo TTY (a new PTY is automatically allocated)
``pty[:path]``
[Linux only] Pseudo TTY (a new PTY is automatically allocated).
If ``path`` is specified, QEMU will create a symbolic link at
that location which points to the new PTY device.
This avoids having to make QMP or HMP monitor queries to find
out what the new PTY device path is.
Note that while QEMU will remove the symlink when it exits
gracefully, it will not do so in case of crashes or on certain
startup errors. It is recommended that the user checks and
removes the symlink after QEMU terminates to account for this.
``none``
No device is allocated. Note that for machine types which