diff mbox

[v4,3/5] char: unix/tcp: Add a non-blocking write handler

Message ID 1272957442-7832-4-git-send-email-amit.shah@redhat.com
State New
Headers show

Commit Message

Amit Shah May 4, 2010, 7:17 a.m. UTC
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(-)

Comments

Gerd Hoffmann May 4, 2010, 7:43 a.m. UTC | #1
On 05/04/10 09:17, Amit Shah 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.

The logic will be pretty much the same for all filehandle-based backends 
on unix.  So maybe create some helper functions, so implementing 
$backend_chr_write_unblocked can be done with just three lines of code?

cheers,
   Gerd
Amit Shah May 4, 2010, 7:56 a.m. UTC | #2
On (Tue) May 04 2010 [09:43:04], Gerd Hoffmann wrote:
> On 05/04/10 09:17, Amit Shah 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.
>
> The logic will be pretty much the same for all filehandle-based backends  
> on unix.  So maybe create some helper functions, so implementing  
> $backend_chr_write_unblocked can be done with just three lines of code?

Yes, that's the next step. Let's push this for now and do that in a
later patch series?

		Amit
Gerd Hoffmann May 4, 2010, 8:13 a.m. UTC | #3
On 05/04/10 09:56, Amit Shah wrote:
>> The logic will be pretty much the same for all filehandle-based backends
>> on unix.  So maybe create some helper functions, so implementing
>> $backend_chr_write_unblocked can be done with just three lines of code?
>
> Yes, that's the next step. Let's push this for now and do that in a
> later patch series?

Fine with me.

cheers,
   Gerd
diff mbox

Patch

diff --git a/qemu-char.c b/qemu-char.c
index 1cae1d2..476bb4e 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2117,11 +2117,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);
@@ -2254,6 +2303,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;