qemu-devel
[Top][All Lists]
Advanced

[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"
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]