qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 1/2] qemu-char: Introduce Buffered driver


From: Luiz Capitulino
Subject: Re: [Qemu-devel] [PATCH 1/2] qemu-char: Introduce Buffered driver
Date: Wed, 10 Nov 2010 10:32:35 -0200

On Wed, 10 Nov 2010 10:26:15 +0100
Markus Armbruster <address@hidden> wrote:

> Luiz Capitulino <address@hidden> writes:
> 
> > This driver handles in-memory qemu-char driver operations, that's,
> > all writes to this driver are stored in an internal buffer. The
> > driver doesn't talk to the external world in any way.
> 
> I'm not so happy with the name "buffered driver".  "Bufferedness" isn't
> what this kind of character device is about.  It's about being connected
> to a memory buffer.
> 
> Consider stdio streams or C++ IOstreams: there are various kinds of
> streams, and they can be buffered or unbuffered.  One kind is the
> "memory" or "string" stream.

Makes sense.

> What about "memory driver"?  "membuf driver"?  "string driver"?

Let's call it MemoryDriver then.

> > Right now it's very simple: it supports only writes. But it can
> > be easily extended to support more operations.
> >
> > This driver is going to be used by the monitor subsystem, which
> > needs to 'emulate' a qemu-char device, so that monitor handlers
> > can be ran without a backing device and have their output stored.
> >
> > TODO: Move buffer growth logic to cutils.
> 
> Would be nice to have this TODO as comment in the code.

True.

> > Signed-off-by: Luiz Capitulino <address@hidden>
> > ---
> >  qemu-char.c |   68 
> > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  qemu-char.h |    6 +++++
> >  2 files changed, 74 insertions(+), 0 deletions(-)
> >
> > diff --git a/qemu-char.c b/qemu-char.c
> > index 6d2dce7..1ca9ccc 100644
> > --- a/qemu-char.c
> > +++ b/qemu-char.c
> > @@ -2279,6 +2279,74 @@ static CharDriverState 
> > *qemu_chr_open_socket(QemuOpts *opts)
> >      return NULL;
> >  }
> >  
> > +/***********************************************************/
> > +/* Buffered chardev */
> > +typedef struct {
> > +    size_t outbuf_size;
> > +    size_t outbuf_capacity;
> > +    uint8_t *outbuf;
> > +} BufferedDriver;
> 
> Out of curiosity: how do you think input should work?  Second buffer?
> Loopback to same buffer?

I was thinking in having a second buffer.

> Maybe the buffer should be a separate data type, with the character
> device type wrapped around its buffer(s).  I'm not asking you to do that
> now.

Seems interesting.

> > +
> > +static int buffered_chr_write(CharDriverState *chr, const uint8_t *buf, 
> > int len)
> > +{
> > +    BufferedDriver *d = chr->opaque;
> > +
> > +    if (d->outbuf_capacity < (d->outbuf_size + len)) {
> 
> Superfluous parenthesis around right operand of <.
> 
> > +        /* grow outbuf */
> > +        d->outbuf_capacity += len;
> > +        d->outbuf_capacity *= 2;
> > +        d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity);
> > +    }
> > +
> > +    memcpy(d->outbuf + d->outbuf_size, buf, len);
> > +    d->outbuf_size += len;
> > +
> > +    return 0;
> 
> Uh, aren't you supposed to return len here?

Yes, but you're reviewing my RFC, I've posted an updated version already:

 http://lists.gnu.org/archive/html/qemu-devel/2010-10/msg02232.html

I think most of your comments still apply, if not please say.

> > +}
> > +
> > +void qemu_chr_init_buffered(CharDriverState *chr)
> > +{
> > +    BufferedDriver *d;
> > +
> > +    d = qemu_mallocz(sizeof(BufferedDriver));
> > +    d->outbuf_capacity = 4096;
> > +    d->outbuf = qemu_mallocz(d->outbuf_capacity);
> > +
> > +    memset(chr, 0, sizeof(*chr));
> > +    chr->opaque = d;
> > +    chr->chr_write = buffered_chr_write;
> > +}
> 
> Unlike normal character drivers, this one isn't accessible via
> qemu_chr_open().  That's why you have qemu_chr_init_buffered() rather
> than qemu_chr_open_buffered().

Yes, and it's simpler that way.

> > +QString *qemu_chr_buffered_to_qs(CharDriverState *chr)
> > +{
> > +    char *str;
> > +    QString *qs;
> > +    BufferedDriver *d = chr->opaque;
> > +
> > +    if (d->outbuf_size == 0) {
> > +        return NULL;
> > +    }
> 
> This is weird.  Shouldn't we return an empty QString when chr contains
> an empty string?

Yeah, will fix.

> > +    str = qemu_malloc(d->outbuf_size + 1);
> > +    memcpy(str, d->outbuf, d->outbuf_size);
> > +    str[d->outbuf_size] = '\0';
> > +
> > +    qs = qstring_from_str(str);
> > +    qemu_free(str);
> > +
> > +    return qs;
> > +}
> 
> While a QString is exactly what you need in PATCH 2/2, it's rather
> special.  Let's split it into the elementary building blocks:
> 
> (1) Find the string stored within the chr.
> (2) Copy it to a newly malloc'ed buffer.
> (3) Wrap a QString around it.  Already exists: qstring_from_str().
> 
> Maybe you'd prefer to keep (1) and (2) fused.  Fine with me.

This function is different in v1, it's quite simple, but it still
returns a QString:

/* assumes the stored data is a string */
QString *qemu_chr_buffered_to_qs(CharDriverState *chr)
{
    BufferedDriver *d = chr->opaque;

    if (d->outbuf_size == 0) {
        return NULL;
    }

    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
}

I'd like to keep things as simple as possible for now, maybe future
users will want to get a raw buffer, maybe not. Let's add it when needed.

> > +
> > +void qemu_chr_close_buffered(CharDriverState *chr)
> > +{
> > +    BufferedDriver *d = chr->opaque;
> > +
> > +    qemu_free(d->outbuf);
> > +    qemu_free(chr->opaque);
> > +    chr->opaque = NULL;
> > +    chr->chr_write = NULL;
> > +}
> 
> Unlike normal character drivers, this one can't be closed with
> qemu_chr_close(), can it?  What happens if someone calls
> qemu_chr_close() on it?

I guess it will explode, because this driver is not in the chardevs list
and our CharDriverState instance is allocated on the stack.

Does a function comment solves the problem or do you have something else
in mind?

> 
> > +
> >  QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
> >  {
> >      char host[65], port[33], width[8], height[8];
> > diff --git a/qemu-char.h b/qemu-char.h
> > index 18ad12b..4467641 100644
> > --- a/qemu-char.h
> > +++ b/qemu-char.h
> > @@ -6,6 +6,7 @@
> >  #include "qemu-option.h"
> >  #include "qemu-config.h"
> >  #include "qobject.h"
> > +#include "qstring.h"
> >  
> >  /* character device */
> >  
> > @@ -100,6 +101,11 @@ CharDriverState *qemu_chr_open_eventfd(int eventfd);
> >  
> >  extern int term_escape_char;
> >  
> > +/* buffered chardev */
> > +void qemu_chr_init_buffered(CharDriverState *chr);
> > +void qemu_chr_close_buffered(CharDriverState *chr);
> > +QString *qemu_chr_buffered_to_qs(CharDriverState *chr);
> > +
> >  /* async I/O support */
> >  
> >  int qemu_set_fd_handler2(int fd,
> 




reply via email to

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