diff --git a/include/char/char.h b/include/char/char.h index c91ce3c98a7a..09ac4014dd46 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -56,6 +56,7 @@ 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); + GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond); void (*chr_update_read_handler)(struct CharDriverState *s); int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); int (*get_msgfd)(struct CharDriverState *s); @@ -152,6 +153,9 @@ void qemu_chr_fe_close(struct CharDriverState *chr); void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3); +guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + GIOFunc func, void *user_data); + /** * @qemu_chr_fe_write: * diff --git a/qemu-char.c b/qemu-char.c index 5a5349111c58..70917438d3ef 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -686,7 +686,11 @@ static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) status = g_io_channel_write_chars(fd, (const gchar *)buf, len, &bytes_written, NULL); if (status != G_IO_STATUS_NORMAL) { - if (status != G_IO_STATUS_AGAIN) { + if (status == G_IO_STATUS_AGAIN) { + errno = EAGAIN; + return -1; + } else { + errno = EINVAL; return -1; } } else if (status == G_IO_STATUS_EOF) { @@ -753,6 +757,12 @@ static int fd_chr_read_poll(void *opaque) return s->max_size; } +static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond) +{ + FDCharDriver *s = chr->opaque; + return g_io_create_watch(s->fd_out, cond); +} + static void fd_chr_update_read_handler(CharDriverState *chr) { FDCharDriver *s = chr->opaque; @@ -796,8 +806,10 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) s = g_malloc0(sizeof(FDCharDriver)); s->fd_in = io_channel_from_fd(fd_in); s->fd_out = io_channel_from_fd(fd_out); + fcntl(fd_out, F_SETFL, O_NONBLOCK); s->chr = chr; chr->opaque = s; + chr->chr_add_watch = fd_chr_add_watch; chr->chr_write = fd_chr_write; chr->chr_update_read_handler = fd_chr_update_read_handler; chr->chr_close = fd_chr_close; @@ -3279,6 +3291,24 @@ void qemu_chr_fe_close(struct CharDriverState *chr) } } +guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + GIOFunc func, void *user_data) +{ + GSource *src; + guint tag; + + if (s->chr_add_watch == NULL) { + return -ENOSYS; + } + + src = s->chr_add_watch(s, cond); + g_source_set_callback(src, (GSourceFunc)func, user_data, NULL); + tag = g_source_attach(src, NULL); + g_source_unref(src); + + return tag; +} + void qemu_chr_delete(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next);