From db39fcf1f690b02d612e2bfc00980700887abe03 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 18 Jun 2014 08:43:55 +0200 Subject: qemu-char: introduce qemu_chr_alloc The next patch will modify this function to initialize state that is common to all backends. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- qemu-char.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'qemu-char.c') diff --git a/qemu-char.c b/qemu-char.c index e4eb985..7e4bd90 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -91,6 +91,12 @@ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = QTAILQ_HEAD_INITIALIZER(chardevs); +CharDriverState *qemu_chr_alloc(void) +{ + CharDriverState *chr = g_malloc0(sizeof(CharDriverState)); + return chr; +} + void qemu_chr_be_event(CharDriverState *s, int event) { /* Keep track if the char device is open */ @@ -282,7 +288,7 @@ static CharDriverState *qemu_chr_open_null(void) { CharDriverState *chr; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); chr->chr_write = null_chr_write; chr->explicit_be_open = true; return chr; @@ -570,7 +576,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) CharDriverState *chr; MuxDriver *d; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); d = g_malloc0(sizeof(MuxDriver)); chr->opaque = d; @@ -945,7 +951,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) CharDriverState *chr; FDCharDriver *s; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); s = g_malloc0(sizeof(FDCharDriver)); s->fd_in = io_channel_from_fd(fd_in); s->fd_out = io_channel_from_fd(fd_out); @@ -1222,7 +1228,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id, close(slave_fd); - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); chr->filename = g_strdup_printf("pty:%s", pty_name); ret->pty = g_strdup(pty_name); @@ -1584,7 +1590,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) drv->fd = fd; drv->mode = IEEE1284_MODE_COMPAT; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; chr->chr_close = pp_close; @@ -1639,7 +1645,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) { CharDriverState *chr; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; @@ -1863,7 +1869,7 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename) CharDriverState *chr; WinCharState *s; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); s = g_malloc0(sizeof(WinCharState)); chr->opaque = s; chr->chr_write = win_chr_write; @@ -1962,7 +1968,7 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) CharDriverState *chr; WinCharState *s; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); s = g_malloc0(sizeof(WinCharState)); chr->opaque = s; chr->chr_write = win_chr_write; @@ -1981,7 +1987,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) CharDriverState *chr; WinCharState *s; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); s = g_malloc0(sizeof(WinCharState)); s->hcom = fd_out; chr->opaque = s; @@ -2137,7 +2143,7 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) DWORD dwMode; int is_console = 0; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); stdio = g_malloc0(sizeof(WinStdioCharState)); stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); @@ -2299,7 +2305,7 @@ static CharDriverState *qemu_chr_open_udp_fd(int fd) CharDriverState *chr = NULL; NetCharDriver *s = NULL; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); s = g_malloc0(sizeof(NetCharDriver)); s->fd = fd; @@ -2850,7 +2856,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, return NULL; } - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); s = g_malloc0(sizeof(TCPCharDriver)); s->connected = 0; @@ -3040,7 +3046,7 @@ static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, CharDriverState *chr; RingBufCharDriver *d; - chr = g_malloc0(sizeof(CharDriverState)); + chr = qemu_chr_alloc(); d = g_malloc(sizeof(*d)); d->size = opts->has_size ? opts->size : 65536; -- cgit v1.1 From 6975b713e695e7f1c24a5437fe71fe45381aeebf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 18 Jun 2014 08:43:56 +0200 Subject: qemu-char: do not call chr_write directly Make the mux always go through qemu_chr_fe_write, so that we'll get the mutex for the underlying chardev. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- qemu-char.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'qemu-char.c') diff --git a/qemu-char.c b/qemu-char.c index 7e4bd90..28ea9f2 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -325,7 +325,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) MuxDriver *d = chr->opaque; int ret; if (!d->timestamps) { - ret = d->drv->chr_write(d->drv, buf, len); + ret = qemu_chr_fe_write(d->drv, buf, len); } else { int i; @@ -347,10 +347,10 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) (secs / 60) % 60, secs % 60, (int)(ti % 1000)); - d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1)); + qemu_chr_fe_write(d->drv, (uint8_t *)buf1, strlen(buf1)); d->linestart = 0; } - ret += d->drv->chr_write(d->drv, buf+i, 1); + ret += qemu_chr_fe_write(d->drv, buf+i, 1); if (buf[i] == '\n') { d->linestart = 1; } @@ -385,13 +385,13 @@ static void mux_print_help(CharDriverState *chr) "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char); } - chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf)); + qemu_chr_fe_write(chr, (uint8_t *)cbuf, strlen(cbuf)); for (i = 0; mux_help[i] != NULL; i++) { for (j=0; mux_help[i][j] != '\0'; j++) { if (mux_help[i][j] == '%') - chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf)); + qemu_chr_fe_write(chr, (uint8_t *)ebuf, strlen(ebuf)); else - chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1); + qemu_chr_fe_write(chr, (uint8_t *)&mux_help[i][j], 1); } } } @@ -416,7 +416,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) case 'x': { const char *term = "QEMU: Terminated\n\r"; - chr->chr_write(chr,(uint8_t *)term,strlen(term)); + qemu_chr_fe_write(chr, (uint8_t *)term, strlen(term)); exit(0); break; } -- cgit v1.1 From 1bb7fe725c5f24a441c93fcffddcf4726f11cab5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 18 Jun 2014 08:43:57 +0200 Subject: qemu-char: move pty_chr_update_read_handler around Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- qemu-char.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'qemu-char.c') diff --git a/qemu-char.c b/qemu-char.c index 28ea9f2..9961b02 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1101,6 +1101,22 @@ static void pty_chr_rearm_timer(CharDriverState *chr, int ms) } } +static void pty_chr_update_read_handler(CharDriverState *chr) +{ + PtyCharDriver *s = chr->opaque; + GPollFD pfd; + + pfd.fd = g_io_channel_unix_get_fd(s->fd); + pfd.events = G_IO_OUT; + pfd.revents = 0; + g_poll(&pfd, 1, 0); + if (pfd.revents & G_IO_HUP) { + pty_chr_state(chr, 0); + } else { + pty_chr_state(chr, 1); + } +} + static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { PtyCharDriver *s = chr->opaque; @@ -1153,22 +1169,6 @@ static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) return TRUE; } -static void pty_chr_update_read_handler(CharDriverState *chr) -{ - PtyCharDriver *s = chr->opaque; - GPollFD pfd; - - pfd.fd = g_io_channel_unix_get_fd(s->fd); - pfd.events = G_IO_OUT; - pfd.revents = 0; - g_poll(&pfd, 1, 0); - if (pfd.revents & G_IO_HUP) { - pty_chr_state(chr, 0); - } else { - pty_chr_state(chr, 1); - } -} - static void pty_chr_state(CharDriverState *chr, int connected) { PtyCharDriver *s = chr->opaque; -- cgit v1.1 From 9005b2a7589540a3733b3abdcfbccfe7746cd1a1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 18 Jun 2014 08:43:58 +0200 Subject: qemu-char: make writes thread-safe This will let threads other than the I/O thread raise QMP events. GIOChannel is thread-safe, and send and receive state is usually well-separated. The only driver that requires some care is the pty driver, where some of the state is shared by the read and write sides. That state is protected with the chr_write_lock too. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- qemu-char.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 12 deletions(-) (limited to 'qemu-char.c') diff --git a/qemu-char.c b/qemu-char.c index 9961b02..a9025e6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -121,7 +121,12 @@ void qemu_chr_be_generic_open(CharDriverState *s) int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) { - return s->chr_write(s, buf, len); + int ret; + + qemu_mutex_lock(&s->chr_write_lock); + ret = s->chr_write(s, buf, len); + qemu_mutex_unlock(&s->chr_write_lock); + return ret; } int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len) @@ -129,6 +134,7 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len) int offset = 0; int res; + qemu_mutex_lock(&s->chr_write_lock); while (offset < len) { do { res = s->chr_write(s, buf + offset, len - offset); @@ -137,17 +143,17 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len) } } while (res == -1 && errno == EAGAIN); - if (res == 0) { + if (res <= 0) { break; } - if (res < 0) { - return res; - } - offset += res; } + qemu_mutex_unlock(&s->chr_write_lock); + if (res < 0) { + return res; + } return offset; } @@ -315,11 +321,14 @@ typedef struct { int prod[MAX_MUX]; int cons[MAX_MUX]; int timestamps; + + /* Protected by the CharDriverState chr_write_lock. */ int linestart; int64_t timestamps_start; } MuxDriver; +/* Called with chr_write_lock held. */ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { MuxDriver *d = chr->opaque; @@ -865,6 +874,7 @@ typedef struct FDCharDriver { QTAILQ_ENTRY(FDCharDriver) node; } FDCharDriver; +/* Called with chr_write_lock held. */ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { FDCharDriver *s = chr->opaque; @@ -1064,12 +1074,14 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) typedef struct { GIOChannel *fd; - int connected; int read_bytes; + + /* Protected by the CharDriverState chr_write_lock. */ + int connected; guint timer_tag; } PtyCharDriver; -static void pty_chr_update_read_handler(CharDriverState *chr); +static void pty_chr_update_read_handler_locked(CharDriverState *chr); static void pty_chr_state(CharDriverState *chr, int connected); static gboolean pty_chr_timer(gpointer opaque) @@ -1077,14 +1089,17 @@ static gboolean pty_chr_timer(gpointer opaque) struct CharDriverState *chr = opaque; PtyCharDriver *s = chr->opaque; + qemu_mutex_lock(&chr->chr_write_lock); s->timer_tag = 0; if (!s->connected) { /* Next poll ... */ - pty_chr_update_read_handler(chr); + pty_chr_update_read_handler_locked(chr); } + qemu_mutex_unlock(&chr->chr_write_lock); return FALSE; } +/* Called with chr_write_lock held. */ static void pty_chr_rearm_timer(CharDriverState *chr, int ms) { PtyCharDriver *s = chr->opaque; @@ -1101,7 +1116,8 @@ static void pty_chr_rearm_timer(CharDriverState *chr, int ms) } } -static void pty_chr_update_read_handler(CharDriverState *chr) +/* Called with chr_write_lock held. */ +static void pty_chr_update_read_handler_locked(CharDriverState *chr) { PtyCharDriver *s = chr->opaque; GPollFD pfd; @@ -1117,13 +1133,21 @@ static void pty_chr_update_read_handler(CharDriverState *chr) } } +static void pty_chr_update_read_handler(CharDriverState *chr) +{ + qemu_mutex_lock(&chr->chr_write_lock); + pty_chr_update_read_handler_locked(chr); + qemu_mutex_unlock(&chr->chr_write_lock); +} + +/* Called with chr_write_lock held. */ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { PtyCharDriver *s = chr->opaque; if (!s->connected) { /* guest sends data, check for (re-)connect */ - pty_chr_update_read_handler(chr); + pty_chr_update_read_handler_locked(chr); return 0; } return io_channel_send(s->fd, buf, len); @@ -1169,6 +1193,7 @@ static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) return TRUE; } +/* Called with chr_write_lock held. */ static void pty_chr_state(CharDriverState *chr, int connected) { PtyCharDriver *s = chr->opaque; @@ -1659,9 +1684,12 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) typedef struct { int max_size; HANDLE hcom, hrecv, hsend; - OVERLAPPED orecv, osend; + OVERLAPPED orecv; BOOL fpipe; DWORD len; + + /* Protected by the CharDriverState chr_write_lock. */ + OVERLAPPED osend; } WinCharState; typedef struct { @@ -1771,6 +1799,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename) return -1; } +/* Called with chr_write_lock held. */ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) { WinCharState *s = chr->opaque; @@ -2213,6 +2242,7 @@ typedef struct { int max_size; } NetCharDriver; +/* Called with chr_write_lock held. */ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { NetCharDriver *s = chr->opaque; @@ -2403,6 +2433,7 @@ static int unix_send_msgfds(CharDriverState *chr, const uint8_t *buf, int len) } #endif +/* Called with chr_write_lock held. */ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { TCPCharDriver *s = chr->opaque; @@ -3000,6 +3031,7 @@ static size_t ringbuf_count(const CharDriverState *chr) return d->prod - d->cons; } +/* Called with chr_write_lock held. */ static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { RingBufCharDriver *d = chr->opaque; @@ -3024,9 +3056,11 @@ static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len) RingBufCharDriver *d = chr->opaque; int i; + qemu_mutex_lock(&chr->chr_write_lock); for (i = 0; i < len && d->cons != d->prod; i++) { buf[i] = d->cbuf[d->cons++ & (d->size - 1)]; } + qemu_mutex_unlock(&chr->chr_write_lock); return i; } -- cgit v1.1