Message ID | 1273009170-17530-5-git-send-email-amit.shah@redhat.com |
---|---|
State | New |
Headers | show |
On 05/04/2010 04:39 PM, Amit Shah wrote: > For char devices whose backing files are open in non-blocking mode, > non-blocking writes can now be made using qemu_chr_write_nb(). > > For non-blocking chardevs, we can return -EAGAIN to callers of > qemu_chr_write_nb(). When the backend is ready to accept more data, > we can let the caller know via a callback. > > -EAGAIN is returned only when the backend's file is non-blocking > and a callback is registered by the caller when invoking > qemu_chr_add_handlers(). > > In case a backend doesn't support non-blocking writes, > qemu_chr_write_nb() invokes qemu_chr_write(). > > Individual callers can update their code to add a callback handler, > call qemu_chr_write_nb() instead of qemu_chr_write() if they wish to > receive -EAGAIN notifications. > > No backend currently supports non-blocking writes. > > Signed-off-by: Amit Shah<amit.shah@redhat.com> > --- > net/socket.c | 4 ++-- > qemu-char.c | 31 ++++++++++++++++++++++++------- > qemu-char.h | 8 ++++++++ > qemu_socket.h | 3 ++- > 4 files changed, 36 insertions(+), 10 deletions(-) > > diff --git a/net/socket.c b/net/socket.c > index 1c4e153..8a401e6 100644 > --- a/net/socket.c > +++ b/net/socket.c > @@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_ > uint32_t len; > len = htonl(size); > > - send_all(s->fd, (const uint8_t *)&len, sizeof(len)); > - return send_all(s->fd, buf, size); > + send_all(s->fd, (const uint8_t *)&len, sizeof(len), false); > + return send_all(s->fd, buf, size, false); > } > > static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size) > diff --git a/qemu-char.c b/qemu-char.c > index decf687..5e4dec3 100644 > --- a/qemu-char.c > +++ b/qemu-char.c > @@ -145,6 +145,16 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) > return s->chr_write(s, buf, len); > } > > +ssize_t qemu_chr_write_nb(CharDriverState *s, const uint8_t *buf, size_t len) > +{ > + if (!s->nonblock) { > + /* Fallback to blocking write if no callback registered */ > + return qemu_chr_write(s, buf, len); > + } > + > + return s->chr_write_nb(s, buf, len); > +} > I really dislike the idea of adding another function for this. Can you explain why you need this functionality for virtio-console and why this functionality isn't needed for everything else? Regards, Anthony Liguori > int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) > { > if (!s->chr_ioctl) > @@ -203,11 +213,15 @@ void qemu_chr_add_handlers(CharDriverState *s, > } > s->chr_can_read = handlers->fd_can_read; > s->chr_read = handlers->fd_read; > + s->chr_write_unblocked = handlers->fd_write_unblocked; > s->chr_event = handlers->fd_event; > s->handler_opaque = opaque; > if (s->chr_update_read_handler) > s->chr_update_read_handler(s); > > + /* We'll set this at connect-time */ > + s->nonblock = false; > + > /* We're connecting to an already opened device, so let's make sure we > also get the open event */ > if (s->opened) { > @@ -499,7 +513,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) > > > #ifdef _WIN32 > -int send_all(int fd, const void *buf, int len1) > +int send_all(int fd, const void *buf, int len1, bool nonblock) > { > int ret, len; > > @@ -526,7 +540,7 @@ int send_all(int fd, const void *buf, int len1) > > #else > > -static int unix_write(int fd, const uint8_t *buf, int len1) > +static int unix_write(int fd, const uint8_t *buf, int len1, bool nonblock) > { > int ret, len; > > @@ -540,6 +554,9 @@ static int unix_write(int fd, const uint8_t *buf, int len1) > if (len1 - len) { > return len1 - len; > } > + if (errno == EAGAIN&& nonblock) { > + return -EAGAIN; > + } > if (errno != EAGAIN) { > return -1; > } > @@ -553,9 +570,9 @@ static int unix_write(int fd, const uint8_t *buf, int len1) > return len1 - len; > } > > -int send_all(int fd, const void *buf, int len1) > +int send_all(int fd, const void *buf, int len1, bool nonblock) > { > - return unix_write(fd, buf, len1); > + return unix_write(fd, buf, len1, nonblock); > } > #endif /* !_WIN32 */ > > @@ -572,7 +589,7 @@ static int stdio_nb_clients = 0; > static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) > { > FDCharDriver *s = chr->opaque; > - return send_all(s->fd_out, buf, len); > + return send_all(s->fd_out, buf, len, false); > } > > static int fd_chr_read_poll(void *opaque) > @@ -884,7 +901,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) > pty_chr_update_read_handler(chr); > return 0; > } > - return send_all(s->fd, buf, len); > + return send_all(s->fd, buf, len, false); > } > > static int pty_chr_read_poll(void *opaque) > @@ -1949,7 +1966,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) > { > TCPCharDriver *s = chr->opaque; > if (s->connected) { > - return send_all(s->fd, buf, len); > + return send_all(s->fd, buf, len, false); > } else { > /* XXX: indicate an error ? */ > return len; > diff --git a/qemu-char.h b/qemu-char.h > index eacb3b9..52f9ef1 100644 > --- a/qemu-char.h > +++ b/qemu-char.h > @@ -1,6 +1,8 @@ > #ifndef QEMU_CHAR_H > #define QEMU_CHAR_H > > +#include<stdbool.h> > + > #include "qemu-common.h" > #include "qemu-queue.h" > #include "qemu-option.h" > @@ -53,12 +55,15 @@ typedef void IOEventHandler(void *opaque, int event); > struct CharDriverState { > void (*init)(struct CharDriverState *s); > int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); > + ssize_t (*chr_write_nb)(struct CharDriverState *s, const uint8_t *buf, > + size_t len); > void (*chr_update_read_handler)(struct CharDriverState *s); > int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); > int (*get_msgfd)(struct CharDriverState *s); > IOEventHandler *chr_event; > IOCanReadHandler *chr_can_read; > IOReadHandler *chr_read; > + IOHandler *chr_write_unblocked; > void *handler_opaque; > void (*chr_send_event)(struct CharDriverState *chr, int event); > void (*chr_close)(struct CharDriverState *chr); > @@ -68,6 +73,8 @@ struct CharDriverState { > char *label; > char *filename; > int opened; > + bool nonblock; > + bool write_blocked; > QTAILQ_ENTRY(CharDriverState) next; > }; > > @@ -85,6 +92,7 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i > void qemu_chr_close(CharDriverState *chr); > void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); > int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); > +ssize_t qemu_chr_write_nb(CharDriverState *s, const uint8_t *buf, size_t len); > void qemu_chr_send_event(CharDriverState *s, int event); > void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers, > void *opaque); > diff --git a/qemu_socket.h b/qemu_socket.h > index 164ae3e..bdf878b 100644 > --- a/qemu_socket.h > +++ b/qemu_socket.h > @@ -23,6 +23,7 @@ int inet_aton(const char *cp, struct in_addr *ia); > #include<arpa/inet.h> > #include<netdb.h> > #include<sys/un.h> > +#include<stdbool.h> > > #define socket_error() errno > #define closesocket(s) close(s) > @@ -35,7 +36,7 @@ int inet_aton(const char *cp, struct in_addr *ia); > int qemu_socket(int domain, int type, int protocol); > int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); > void socket_set_nonblock(int fd); > -int send_all(int fd, const void *buf, int len1); > +int send_all(int fd, const void *buf, int len1, bool nonblock); > > /* New, ipv6-ready socket helper functions, see qemu-sockets.c */ > int inet_listen_opts(QemuOpts *opts, int port_offset); >
On (Wed) May 05 2010 [08:16:37], Anthony Liguori wrote: > On 05/04/2010 04:39 PM, Amit Shah wrote: >> For char devices whose backing files are open in non-blocking mode, >> non-blocking writes can now be made using qemu_chr_write_nb(). >> >> For non-blocking chardevs, we can return -EAGAIN to callers of >> qemu_chr_write_nb(). When the backend is ready to accept more data, >> we can let the caller know via a callback. >> >> -EAGAIN is returned only when the backend's file is non-blocking >> and a callback is registered by the caller when invoking >> qemu_chr_add_handlers(). >> >> In case a backend doesn't support non-blocking writes, >> qemu_chr_write_nb() invokes qemu_chr_write(). >> >> Individual callers can update their code to add a callback handler, >> call qemu_chr_write_nb() instead of qemu_chr_write() if they wish to >> receive -EAGAIN notifications. >> >> No backend currently supports non-blocking writes. >> >> Signed-off-by: Amit Shah<amit.shah@redhat.com> >> >> +ssize_t qemu_chr_write_nb(CharDriverState *s, const uint8_t *buf, size_t len) >> +{ >> + if (!s->nonblock) { >> + /* Fallback to blocking write if no callback registered */ >> + return qemu_chr_write(s, buf, len); >> + } >> + >> + return s->chr_write_nb(s, buf, len); >> +} >> > > I really dislike the idea of adding another function for this. This suggestion came from Gerd to separate out a write() that blocks and a write_nb() that doesn't block on -EAGAIN. > Can you > explain why you need this functionality for virtio-console and why this > functionality isn't needed for everything else? I don't know about everything else; but for virtio-console, a fast guest could swamp a host chardev with data and while the host chardev blocks to flush out all the data, a notification to ask the guest to stop is needed so that we don't lose any data. (virtio-console asks virtio-serial to throttle any more data, and virtio-serial doesn't send any more data to this port till it signals otherwise. The guest, in the meantime, keeps filling its queue till the queue is full. Once that happens, writes in guests return with -EAGAIN.) Amit
> I really dislike the idea of adding another function for this. Can you > explain why you need this functionality for virtio-console and why this > functionality isn't needed for everything else? This functionality should (in principle) be used by all serial port implementations. Physical serial ports are sufficiently crufty and low-performance that noone actually uses them nowadays. I expect that the only significant real-world use is for serial consoles, which never send enough data to care that writes stall the whole machine. With virtio-serial we've made serial ports a viable solution to a whole range of problems. It's likely that applications that may send nontrivial amounts of data, or clients will not be ready to process the data immediately. Paul
On 05/05/2010 08:34 AM, Paul Brook wrote: >> I really dislike the idea of adding another function for this. Can you >> explain why you need this functionality for virtio-console and why this >> functionality isn't needed for everything else? >> > This functionality should (in principle) be used by all serial port > implementations. > > Physical serial ports are sufficiently crufty and low-performance that noone > actually uses them nowadays. I expect that the only significant real-world > use is for serial consoles, which never send enough data to care that writes > stall the whole machine. > We don't implement control flow in the character driver layer today. Different backends use different policies. Some drop data (like pty) while other block (like tcp). This patch adds optional control flow in a pretty crufty way to *some* backends but not all. This just adds a bunch of complexity that will certainly introduce bugs. If we're going to make the char drivers implement control flow, then I think we should do it universally--not as an optional feature. For devices that can't participate in control flow, we should decide where the policy should be implemented (front-end or back-end) and in either approach, it's easy enough to make dropping data or blocking a choice. Regards, Anthony Liguori > With virtio-serial we've made serial ports a viable solution to a whole range > of problems. It's likely that applications that may send nontrivial amounts > of data, or clients will not be ready to process the data immediately. > > Paul >
> On 05/05/2010 08:34 AM, Paul Brook wrote: > >> I really dislike the idea of adding another function for this. Can you > >> explain why you need this functionality for virtio-console and why this > >> functionality isn't needed for everything else? > > > > This functionality should (in principle) be used by all serial port > > implementations. > > > > Physical serial ports are sufficiently crufty and low-performance that > > noone actually uses them nowadays. I expect that the only significant > > real-world use is for serial consoles, which never send enough data to > > care that writes stall the whole machine. > > We don't implement control flow in the character driver layer today. > Different backends use different policies. Some drop data (like pty) > while other block (like tcp). Really? I thought data was only dropped when no client was connected, and that there was a user visible option to control this. Either way, I agree that this should be done consistently. > This patch adds optional control flow in a pretty crufty way to *some* > backends but not all. This just adds a bunch of complexity that will > certainly introduce bugs. I admit I've only really looked at the device emulation side of the interface, not the chardev backend implementation. Paul
>> + return s->chr_write_nb(s, buf, len); >> +} > > I really dislike the idea of adding another function for this. Having a explicit function for non-blocking mode IMHO is much better. It makes things more clear when reading the code. Previous approach was to check for O_NONBLOCK (extra syscall) and behave differently depending on whenever it is set or not (too much hidden magic). > Can you > explain why you need this functionality for virtio-console and why this > functionality isn't needed for everything else? virtio-console is just the first user. 16550 emulation can use that too. With the blocking interface you'll stall the guest (sitting in the blocking write syscall) in case the outgoing pipe is full. With the non-blocking interface you can simply delay the "you can send more data" signal (update status register + raise IRQ) until you can actually accept more data. Meanwhile the guest can continue to run and do something else. Basically it allows to implement sane flow control. cheers, Gerd
On 05/05/10 15:53, Anthony Liguori wrote: > This patch adds optional control flow in a pretty crufty way to *some* > backends but not all. This just adds a bunch of complexity that will > certainly introduce bugs. Amit plans to add support to the others as well. Beside that there is a clearly defined backup plan: In case the non-blocking interface isn't supported by $chardev it will fallback to use the blocking mode. cheers, Gerd
On 05/05/2010 01:40 PM, Gerd Hoffmann wrote: >>> + return s->chr_write_nb(s, buf, len); >>> +} >> >> I really dislike the idea of adding another function for this. > > Having a explicit function for non-blocking mode IMHO is much better. > It makes things more clear when reading the code. > > Previous approach was to check for O_NONBLOCK (extra syscall) and > behave differently depending on whenever it is set or not (too much > hidden magic). > >> Can you >> explain why you need this functionality for virtio-console and why this >> functionality isn't needed for everything else? > > virtio-console is just the first user. 16550 emulation can use that > too. With the blocking interface you'll stall the guest (sitting in > the blocking write syscall) in case the outgoing pipe is full. With > the non-blocking interface you can simply delay the "you can send more > data" signal (update status register + raise IRQ) until you can > actually accept more data. Meanwhile the guest can continue to run > and do something else. Basically it allows to implement sane flow > control. The use of char drivers is dominated by a small number of use cases which include serial ports, the monitor, and QMP. In all of those cases, the devices can and should participate in control flow. IMHO, we should make control flow part of the standard interface and fix all users appropriately. I've seen blocking result in frozen guests many times in real deployments. It's never the right thing to do as far as I can tell. Regards, Anthony Liguori > cheers, > Gerd >
On 05/05/2010 01:43 PM, Gerd Hoffmann wrote: > On 05/05/10 15:53, Anthony Liguori wrote: >> This patch adds optional control flow in a pretty crufty way to *some* >> backends but not all. This just adds a bunch of complexity that will >> certainly introduce bugs. > > Amit plans to add support to the others as well. Beside that there is > a clearly defined backup plan: In case the non-blocking interface > isn't supported by $chardev it will fallback to use the blocking mode. If we have a second interface, we'll have two interfaces forever. I'd rather see us aggressive remove the blocking interface instead of introducing a second interface. Regards, Anthony Liguori > cheers, > Gerd >
On 05/05/10 20:49, Anthony Liguori wrote: > On 05/05/2010 01:43 PM, Gerd Hoffmann wrote: >> On 05/05/10 15:53, Anthony Liguori wrote: >>> This patch adds optional control flow in a pretty crufty way to *some* >>> backends but not all. This just adds a bunch of complexity that will >>> certainly introduce bugs. >> >> Amit plans to add support to the others as well. Beside that there is >> a clearly defined backup plan: In case the non-blocking interface >> isn't supported by $chardev it will fallback to use the blocking mode. > > If we have a second interface, we'll have two interfaces forever. I'd > rather see us aggressive remove the blocking interface instead of > introducing a second interface. I'm all for killing the blocking interface. Problem is that converting over all users isn't exactly trivial and we have plenty of them. IMHO it isn't realistic to do the switch with a single patch series. cheers, Gerd
On 05/05/2010 02:16 PM, Gerd Hoffmann wrote: > On 05/05/10 20:49, Anthony Liguori wrote: >> On 05/05/2010 01:43 PM, Gerd Hoffmann wrote: >>> On 05/05/10 15:53, Anthony Liguori wrote: >>>> This patch adds optional control flow in a pretty crufty way to *some* >>>> backends but not all. This just adds a bunch of complexity that will >>>> certainly introduce bugs. >>> >>> Amit plans to add support to the others as well. Beside that there is >>> a clearly defined backup plan: In case the non-blocking interface >>> isn't supported by $chardev it will fallback to use the blocking mode. >> >> If we have a second interface, we'll have two interfaces forever. I'd >> rather see us aggressive remove the blocking interface instead of >> introducing a second interface. > > I'm all for killing the blocking interface. Problem is that > converting over all users isn't exactly trivial and we have plenty of > them. IMHO it isn't realistic to do the switch with a single patch > series. If we're agreed we ought to kill the blocking interface, let's define a new proper interface, rename all previous users to something ugly and deprecated, and approach it that way. Let's make it clear what interfaces are supported and which interfaces are scheduled to be removed. Regards, Anthony Liguori > cheers, > Gerd >
>> I'm all for killing the blocking interface. Problem is that converting >> over all users isn't exactly trivial and we have plenty of them. IMHO >> it isn't realistic to do the switch with a single patch series. > > If we're agreed we ought to kill the blocking interface, let's define a > new proper interface, rename all previous users to something ugly and > deprecated, and approach it that way. __attribute__ ((deprecated)) ? cheers, Gerd
diff --git a/net/socket.c b/net/socket.c index 1c4e153..8a401e6 100644 --- a/net/socket.c +++ b/net/socket.c @@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_ uint32_t len; len = htonl(size); - send_all(s->fd, (const uint8_t *)&len, sizeof(len)); - return send_all(s->fd, buf, size); + send_all(s->fd, (const uint8_t *)&len, sizeof(len), false); + return send_all(s->fd, buf, size, false); } static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size) diff --git a/qemu-char.c b/qemu-char.c index decf687..5e4dec3 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -145,6 +145,16 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) return s->chr_write(s, buf, len); } +ssize_t qemu_chr_write_nb(CharDriverState *s, const uint8_t *buf, size_t len) +{ + if (!s->nonblock) { + /* Fallback to blocking write if no callback registered */ + return qemu_chr_write(s, buf, len); + } + + return s->chr_write_nb(s, buf, len); +} + int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) { if (!s->chr_ioctl) @@ -203,11 +213,15 @@ void qemu_chr_add_handlers(CharDriverState *s, } s->chr_can_read = handlers->fd_can_read; s->chr_read = handlers->fd_read; + s->chr_write_unblocked = handlers->fd_write_unblocked; s->chr_event = handlers->fd_event; s->handler_opaque = opaque; if (s->chr_update_read_handler) s->chr_update_read_handler(s); + /* We'll set this at connect-time */ + s->nonblock = false; + /* We're connecting to an already opened device, so let's make sure we also get the open event */ if (s->opened) { @@ -499,7 +513,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) #ifdef _WIN32 -int send_all(int fd, const void *buf, int len1) +int send_all(int fd, const void *buf, int len1, bool nonblock) { int ret, len; @@ -526,7 +540,7 @@ int send_all(int fd, const void *buf, int len1) #else -static int unix_write(int fd, const uint8_t *buf, int len1) +static int unix_write(int fd, const uint8_t *buf, int len1, bool nonblock) { int ret, len; @@ -540,6 +554,9 @@ static int unix_write(int fd, const uint8_t *buf, int len1) if (len1 - len) { return len1 - len; } + if (errno == EAGAIN && nonblock) { + return -EAGAIN; + } if (errno != EAGAIN) { return -1; } @@ -553,9 +570,9 @@ static int unix_write(int fd, const uint8_t *buf, int len1) return len1 - len; } -int send_all(int fd, const void *buf, int len1) +int send_all(int fd, const void *buf, int len1, bool nonblock) { - return unix_write(fd, buf, len1); + return unix_write(fd, buf, len1, nonblock); } #endif /* !_WIN32 */ @@ -572,7 +589,7 @@ static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { FDCharDriver *s = chr->opaque; - return send_all(s->fd_out, buf, len); + return send_all(s->fd_out, buf, len, false); } static int fd_chr_read_poll(void *opaque) @@ -884,7 +901,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) pty_chr_update_read_handler(chr); return 0; } - return send_all(s->fd, buf, len); + return send_all(s->fd, buf, len, false); } static int pty_chr_read_poll(void *opaque) @@ -1949,7 +1966,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { TCPCharDriver *s = chr->opaque; if (s->connected) { - return send_all(s->fd, buf, len); + return send_all(s->fd, buf, len, false); } else { /* XXX: indicate an error ? */ return len; diff --git a/qemu-char.h b/qemu-char.h index eacb3b9..52f9ef1 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -1,6 +1,8 @@ #ifndef QEMU_CHAR_H #define QEMU_CHAR_H +#include <stdbool.h> + #include "qemu-common.h" #include "qemu-queue.h" #include "qemu-option.h" @@ -53,12 +55,15 @@ typedef void IOEventHandler(void *opaque, int event); struct CharDriverState { void (*init)(struct CharDriverState *s); int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); + ssize_t (*chr_write_nb)(struct CharDriverState *s, const uint8_t *buf, + size_t len); void (*chr_update_read_handler)(struct CharDriverState *s); int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); int (*get_msgfd)(struct CharDriverState *s); IOEventHandler *chr_event; IOCanReadHandler *chr_can_read; IOReadHandler *chr_read; + IOHandler *chr_write_unblocked; void *handler_opaque; void (*chr_send_event)(struct CharDriverState *chr, int event); void (*chr_close)(struct CharDriverState *chr); @@ -68,6 +73,8 @@ struct CharDriverState { char *label; char *filename; int opened; + bool nonblock; + bool write_blocked; QTAILQ_ENTRY(CharDriverState) next; }; @@ -85,6 +92,7 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i void qemu_chr_close(CharDriverState *chr); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); +ssize_t qemu_chr_write_nb(CharDriverState *s, const uint8_t *buf, size_t len); void qemu_chr_send_event(CharDriverState *s, int event); void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers, void *opaque); diff --git a/qemu_socket.h b/qemu_socket.h index 164ae3e..bdf878b 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -23,6 +23,7 @@ int inet_aton(const char *cp, struct in_addr *ia); #include <arpa/inet.h> #include <netdb.h> #include <sys/un.h> +#include <stdbool.h> #define socket_error() errno #define closesocket(s) close(s) @@ -35,7 +36,7 @@ int inet_aton(const char *cp, struct in_addr *ia); int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); void socket_set_nonblock(int fd); -int send_all(int fd, const void *buf, int len1); +int send_all(int fd, const void *buf, int len1, bool nonblock); /* New, ipv6-ready socket helper functions, see qemu-sockets.c */ int inet_listen_opts(QemuOpts *opts, int port_offset);
For char devices whose backing files are open in non-blocking mode, non-blocking writes can now be made using qemu_chr_write_nb(). For non-blocking chardevs, we can return -EAGAIN to callers of qemu_chr_write_nb(). When the backend is ready to accept more data, we can let the caller know via a callback. -EAGAIN is returned only when the backend's file is non-blocking and a callback is registered by the caller when invoking qemu_chr_add_handlers(). In case a backend doesn't support non-blocking writes, qemu_chr_write_nb() invokes qemu_chr_write(). Individual callers can update their code to add a callback handler, call qemu_chr_write_nb() instead of qemu_chr_write() if they wish to receive -EAGAIN notifications. No backend currently supports non-blocking writes. Signed-off-by: Amit Shah <amit.shah@redhat.com> --- net/socket.c | 4 ++-- qemu-char.c | 31 ++++++++++++++++++++++++------- qemu-char.h | 8 ++++++++ qemu_socket.h | 3 ++- 4 files changed, 36 insertions(+), 10 deletions(-)