Patchwork [v6,5/6] char: unix/tcp: Add a non-blocking write handler

login
register
mail settings
Submitter Amit Shah
Date May 4, 2010, 6:23 p.m.
Message ID <1272997439-9675-6-git-send-email-amit.shah@redhat.com>
Download mbox | patch
Permalink /patch/51662/
State New
Headers show

Comments

Amit Shah - May 4, 2010, 6:23 p.m.
Add a non-blocking write handler that can return with -EAGAIN to the
caller and also callback when the socket becomes writable.

Non-blocking writes are only enabled for sockets that are opened in
non-blocking mode and only for callers that have registered a callback
handler for resuming writes.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 qemu-char.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 50 insertions(+), 0 deletions(-)
Juan Quintela - May 4, 2010, 7:54 p.m.
Amit Shah <amit.shah@redhat.com> wrote:
> Add a non-blocking write handler that can return with -EAGAIN to the
> caller and also callback when the socket becomes writable.
>
> Non-blocking writes are only enabled for sockets that are opened in
> non-blocking mode and only for callers that have registered a callback
> handler for resuming writes.
>
> Signed-off-by: Amit Shah <amit.shah@redhat.com>

I 

>  static void tcp_chr_connect(void *opaque)
>  {
>      CharDriverState *chr = opaque;
>      TCPCharDriver *s = chr->opaque;
> +    IOHandler *write_cb;
> +    int flags;
> +    bool nonblock;
> +
> +    flags = fcntl(s->fd, F_GETFL);
> +    if (flags == -1) {
> +        flags = 0;
> +    }
> +    nonblock = flags & O_NONBLOCK;
> +
> +    write_cb = NULL;
> +    chr->nonblock = false;
> +    if (nonblock && chr->chr_write_unblocked) {
> +        write_cb = chr->chr_write_unblocked;
> +        chr->nonblock = true;
> +    }
>  
> +    chr->write_blocked = false;
>      s->connected = 1;
>      qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,

write_cb is a write-only variable, no?
Amit Shah - May 4, 2010, 7:58 p.m.
On (Tue) May 04 2010 [21:54:09], Juan Quintela wrote:
> >  static void tcp_chr_connect(void *opaque)
> >  {
> >      CharDriverState *chr = opaque;
> >      TCPCharDriver *s = chr->opaque;
> > +    IOHandler *write_cb;
> > +    int flags;
> > +    bool nonblock;
> > +
> > +    flags = fcntl(s->fd, F_GETFL);
> > +    if (flags == -1) {
> > +        flags = 0;
> > +    }
> > +    nonblock = flags & O_NONBLOCK;
> > +
> > +    write_cb = NULL;
> > +    chr->nonblock = false;
> > +    if (nonblock && chr->chr_write_unblocked) {
> > +        write_cb = chr->chr_write_unblocked;
> > +        chr->nonblock = true;
> > +    }
> >  
> > +    chr->write_blocked = false;
> >      s->connected = 1;
> >      qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
> 
> write_cb is a write-only variable, no?

Leftover from previous design.

I'll clean this up in the next series (already applied to my local
branch).

Thanks,
		Amit

Patch

diff --git a/qemu-char.c b/qemu-char.c
index e6934f6..da70b9b 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2129,11 +2129,60 @@  static void tcp_chr_read(void *opaque)
     }
 }
 
+static void tcp_chr_write_unblocked(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+
+    assert(chr->write_blocked && chr->chr_write_unblocked);
+
+    chr->write_blocked = false;
+    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, tcp_chr_read, NULL, chr);
+    chr->chr_write_unblocked(chr->handler_opaque);
+}
+
+static ssize_t tcp_chr_write_nb(CharDriverState *chr, const uint8_t *buf,
+                                size_t len)
+{
+    TCPCharDriver *s = chr->opaque;
+    ssize_t ret;
+
+    if (!s->connected) {
+        /* XXX: indicate an error? */
+        return len;
+    }
+
+    ret = send_all(s->fd, buf, len, true);
+    if (ret == -EAGAIN) {
+        chr->write_blocked = true;
+        qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
+                             tcp_chr_read, tcp_chr_write_unblocked, chr);
+    }
+    return ret;
+}
+
 static void tcp_chr_connect(void *opaque)
 {
     CharDriverState *chr = opaque;
     TCPCharDriver *s = chr->opaque;
+    IOHandler *write_cb;
+    int flags;
+    bool nonblock;
+
+    flags = fcntl(s->fd, F_GETFL);
+    if (flags == -1) {
+        flags = 0;
+    }
+    nonblock = flags & O_NONBLOCK;
+
+    write_cb = NULL;
+    chr->nonblock = false;
+    if (nonblock && chr->chr_write_unblocked) {
+        write_cb = chr->chr_write_unblocked;
+        chr->nonblock = true;
+    }
 
+    chr->write_blocked = false;
     s->connected = 1;
     qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
                          tcp_chr_read, NULL, chr);
@@ -2266,6 +2315,7 @@  static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
 
     chr->opaque = s;
     chr->chr_write = tcp_chr_write;
+    chr->chr_write_nb = tcp_chr_write_nb;
     chr->chr_close = tcp_chr_close;
     chr->get_msgfd = tcp_get_msgfd;