[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] Add 'maxqdepth' as an option to tty character d
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH] Add 'maxqdepth' as an option to tty character devices. |
Date: |
Mon, 06 May 2013 15:47:15 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130311 Thunderbird/17.0.4 |
Il 06/05/2013 15:43, John Baboval ha scritto:
> From: "John V. Baboval" <address@hidden>
>
> This parameter will cause writes to tty backed chardevs to return
> -EAGAIN if the backing tty has buffered more than the specified
> number of characters. When data is sent, the TIOCOUTQ ioctl is invoked
> to determine the current TTY output buffer depth.
>
> Background:
>
> Some devices use DTR/DSR as flow control. (eg. Check/Receipt
> printers with some POS software). When the device de-asserts
> DTR, the guest OS notifies the application and new data is blocked.
> When running on a QEMU serial port backed by a TTY, though the guest
> stops transmitting, all the characters in the TTY output buffer are
> still sent. The device buffer overflows and data is lost. In this
> case the user could set maxqdepth=1.
>
> Signed-off-by: John Baboval <address@hidden>
> ---
> include/sysemu/char.h | 2 ++
> qapi-schema.json | 5 ++++-
> qemu-char.c | 40 +++++++++++++++++++++++++++++++++++++++-
> qemu-options.hx | 4 ++--
> 4 files changed, 47 insertions(+), 4 deletions(-)
>
> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index 5e42c90..a94c1fb 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -43,6 +43,7 @@ typedef struct {
>
> #define CHR_IOCTL_SERIAL_SET_TIOCM 13
> #define CHR_IOCTL_SERIAL_GET_TIOCM 14
> +#define CHR_IOCTL_SERIAL_TIOCOUTQ 15
>
> #define CHR_TIOCM_CTS 0x020
> #define CHR_TIOCM_CAR 0x040
> @@ -77,6 +78,7 @@ struct CharDriverState {
> int fe_open;
> int explicit_fe_open;
> int avail_connections;
> + uint32_t maxqdepth;
> QemuOpts *opts;
> QTAILQ_ENTRY(CharDriverState) next;
> };
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 7797400..029e7c9 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -3182,11 +3182,14 @@
> #
> # @device: The name of the special file for the device,
> # i.e. /dev/ttyS0 on Unix or COM1: on Windows
> +# @maxqdepth: The maximum depth of the underlying tty
> + output queue (Unix)
> # @type: What kind of device this is.
> #
> # Since: 1.4
> ##
> -{ 'type': 'ChardevHostdev', 'data': { 'device' : 'str' } }
> +{ 'type': 'ChardevHostdev', 'data': { 'device' : 'str',
> + 'maxqdepth' : 'int' } }
This needs to be optional for backwards compatibility. You can check
serial->has_maxqdepth and use a default value of -1 if it is true...
>
> ##
> # @ChardevSocket:
> diff --git a/qemu-char.c b/qemu-char.c
> index 64e824d..e2e4217 100644
> --- a/qemu-char.c
> +++ b/qemu-char.c
> @@ -782,6 +782,7 @@ typedef struct FDCharDriver {
> GIOChannel *fd_in, *fd_out;
> guint fd_in_tag;
> int max_size;
> + int tiocoutq_failed;
> QTAILQ_ENTRY(FDCharDriver) node;
> } FDCharDriver;
>
> @@ -1260,6 +1261,22 @@ static CharDriverState *qemu_chr_open_pty(const char
> *id,
> return chr;
> }
>
> +static int tty_serial_write(CharDriverState *chr, const uint8_t *buf, int
> len)
> +{
> + FDCharDriver *s = chr->opaque;
> + uint32_t inflight = 0;
> +
> + qemu_chr_fe_ioctl(chr, CHR_IOCTL_SERIAL_TIOCOUTQ, &inflight);
> + if (inflight >= chr->maxqdepth)
> + return -EAGAIN;
> +
> + if (inflight + len > chr->maxqdepth) {
> + len = chr->maxqdepth - inflight;
> + }
> +
> + return io_channel_send(s->fd_out, buf, len);
> +}
> +
> static void tty_serial_init(int fd, int speed,
> int parity, int data_bits, int stop_bits)
> {
> @@ -1438,6 +1455,16 @@ static int tty_serial_ioctl(CharDriverState *chr, int
> cmd, void *arg)
> ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMSET, &targ);
> }
> break;
> + case CHR_IOCTL_SERIAL_TIOCOUTQ:
> + {
> + if (!s->tiocoutq_failed)
> + s->tiocoutq_failed =
> ioctl(g_io_channel_unix_get_fd(s->fd_in),
> + TIOCOUTQ, arg);
> +
> + if (s->tiocoutq_failed)
> + *(unsigned int *)arg = 0;
> + }
> + break;
> default:
> return -ENOTSUP;
> }
> @@ -1466,6 +1493,7 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd)
>
> tty_serial_init(fd, 115200, 'N', 8, 1);
> chr = qemu_chr_open_fd(fd, fd);
> + chr->chr_write = tty_serial_write;
> chr->chr_ioctl = tty_serial_ioctl;
> chr->chr_close = qemu_chr_close_tty;
> return chr;
> @@ -3172,6 +3200,8 @@ static void qemu_chr_parse_serial(QemuOpts *opts,
> ChardevBackend *backend,
> }
> backend->serial = g_new0(ChardevHostdev, 1);
> backend->serial->device = g_strdup(device);
> + backend->serial->maxqdepth =
> + qemu_opt_get_number(opts, "maxqdepth", -1);
... and also set has_maxqdepth here.
Thanks,
Paolo
> }
>
> static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
> @@ -3575,6 +3605,9 @@ QemuOptsList qemu_chardev_opts = {
> },{
> .name = "size",
> .type = QEMU_OPT_SIZE,
> + },{
> + .name = "maxqdepth",
> + .type = QEMU_OPT_NUMBER,
> },
> { /* end of list */ }
> },
> @@ -3653,6 +3686,7 @@ static CharDriverState
> *qmp_chardev_open_serial(ChardevHostdev *serial,
> Error **errp)
> {
> #ifdef HAVE_CHARDEV_TTY
> + CharDriverState *chr;
> int fd;
>
> fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
> @@ -3660,7 +3694,11 @@ static CharDriverState
> *qmp_chardev_open_serial(ChardevHostdev *serial,
> return NULL;
> }
> qemu_set_nonblock(fd);
> - return qemu_chr_open_tty_fd(fd);
> + chr = qemu_chr_open_tty_fd(fd);
> + if (chr) {
> + chr->maxqdepth = serial->maxqdepth;
> + }
> + return chr;
> #else
> error_setg(errp, "character device backend type 'serial' not supported");
> return NULL;
> diff --git a/qemu-options.hx b/qemu-options.hx
> index e86cc24..c522f13 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1792,8 +1792,8 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
> #endif
> #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
> || defined(__NetBSD__) || defined(__OpenBSD__) ||
> defined(__DragonFly__)
> - "-chardev serial,id=id,path=path[,mux=on|off]\n"
> - "-chardev tty,id=id,path=path[,mux=on|off]\n"
> + "-chardev serial,id=id,path=path[,mux=on|off][,maxqdepth=count]\n"
> + "-chardev tty,id=id,path=path[,mux=on|off][,maxqdepth=count]\n"
> #endif
> #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
> "-chardev parallel,id=id,path=path[,mux=on|off]\n"
>