All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marc-André Lureau" <marcandre.lureau@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>,
	peter.maydell@linaro.org,
	"Artem Pisarenko" <artem.k.pisarenko@gmail.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>
Subject: [Qemu-devel] [PULL 17/18] chardev: fix mess in OPENED/CLOSED events when muxed
Date: Thu,  7 Feb 2019 17:06:16 +0100	[thread overview]
Message-ID: <20190207160617.1142-18-marcandre.lureau@redhat.com> (raw)
In-Reply-To: <20190207160617.1142-1-marcandre.lureau@redhat.com>

From: Artem Pisarenko <artem.k.pisarenko@gmail.com>

When chardev is multiplexed (mux=on) there are a lot of cases where
CHR_EVENT_OPENED/CHR_EVENT_CLOSED events pairing (expected from
frontend side) is broken. There are either generation of multiple
repeated or extra CHR_EVENT_OPENED events, or CHR_EVENT_CLOSED just
isn't generated at all.
This is mostly because 'qemu_chr_fe_set_handlers()' function makes its
own (and often wrong) implicit decision on updated frontend state and
invokes 'fd_event' callback with 'CHR_EVENT_OPENED'. And even worse,
it doesn't do symmetric action in opposite direction, as someone may
expect (i.e. it doesn't invoke previously set 'fd_event' with
'CHR_EVENT_CLOSED'). Muxed chardev uses trick by calling this function
again to replace callback handlers with its own ones, but it doesn't
account for such side effect.
Fix that using extended version of this function with added argument
for disabling side effect and keep original function for compatibility
with lots of frontends already using this interface and being
"tolerant" to its side effects.
One more source of event duplication is just line of code in
char-mux.c, which does far more than comment above says (obvious fix).

Signed-off-by: Artem Pisarenko <artem.k.pisarenko@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <7dde6abbd21682857f8294644013173c0b9949b3.1541507990.git.artem.k.pisarenko@gmail.com>
---
 include/chardev/char-fe.h | 18 +++++++++++++++++-
 chardev/char-fe.c         | 33 ++++++++++++++++++++++++---------
 chardev/char-mux.c        | 16 ++++++++--------
 3 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index 46c997d352..c1b7fd9a95 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -67,7 +67,7 @@ bool qemu_chr_fe_backend_connected(CharBackend *be);
 bool qemu_chr_fe_backend_open(CharBackend *be);
 
 /**
- * qemu_chr_fe_set_handlers:
+ * qemu_chr_fe_set_handlers_full:
  * @b: a CharBackend
  * @fd_can_read: callback to get the amount of data the frontend may
  *               receive
@@ -79,12 +79,28 @@ bool qemu_chr_fe_backend_open(CharBackend *be);
  * @context: a main loop context or NULL for the default
  * @set_open: whether to call qemu_chr_fe_set_open() implicitely when
  * any of the handler is non-NULL
+ * @sync_state: whether to issue event callback with updated state
  *
  * Set the front end char handlers. The front end takes the focus if
  * any of the handler is non-NULL.
  *
  * Without associated Chardev, nothing is changed.
  */
+void qemu_chr_fe_set_handlers_full(CharBackend *b,
+                                   IOCanReadHandler *fd_can_read,
+                                   IOReadHandler *fd_read,
+                                   IOEventHandler *fd_event,
+                                   BackendChangeHandler *be_change,
+                                   void *opaque,
+                                   GMainContext *context,
+                                   bool set_open,
+                                   bool sync_state);
+
+/**
+ * qemu_chr_fe_set_handlers:
+ *
+ * Version of qemu_chr_fe_set_handlers_full() with sync_state = true.
+ */
 void qemu_chr_fe_set_handlers(CharBackend *b,
                               IOCanReadHandler *fd_can_read,
                               IOReadHandler *fd_read,
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index a8931f7afd..b7bcbd59c0 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -246,14 +246,15 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
     }
 }
 
-void qemu_chr_fe_set_handlers(CharBackend *b,
-                              IOCanReadHandler *fd_can_read,
-                              IOReadHandler *fd_read,
-                              IOEventHandler *fd_event,
-                              BackendChangeHandler *be_change,
-                              void *opaque,
-                              GMainContext *context,
-                              bool set_open)
+void qemu_chr_fe_set_handlers_full(CharBackend *b,
+                                   IOCanReadHandler *fd_can_read,
+                                   IOReadHandler *fd_read,
+                                   IOEventHandler *fd_event,
+                                   BackendChangeHandler *be_change,
+                                   void *opaque,
+                                   GMainContext *context,
+                                   bool set_open,
+                                   bool sync_state)
 {
     Chardev *s;
     int fe_open;
@@ -285,7 +286,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         qemu_chr_fe_take_focus(b);
         /* We're connecting to an already opened device, so let's make sure we
            also get the open event */
-        if (s->be_open) {
+        if (sync_state && s->be_open) {
             qemu_chr_be_event(s, CHR_EVENT_OPENED);
         }
     }
@@ -295,6 +296,20 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
     }
 }
 
+void qemu_chr_fe_set_handlers(CharBackend *b,
+                              IOCanReadHandler *fd_can_read,
+                              IOReadHandler *fd_read,
+                              IOEventHandler *fd_event,
+                              BackendChangeHandler *be_change,
+                              void *opaque,
+                              GMainContext *context,
+                              bool set_open)
+{
+    qemu_chr_fe_set_handlers_full(b, fd_can_read, fd_read, fd_event, be_change,
+                                  opaque, context, set_open,
+                                  true);
+}
+
 void qemu_chr_fe_take_focus(CharBackend *b)
 {
     if (!b->chr) {
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 6055e76293..1199d32674 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -283,13 +283,13 @@ void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
     MuxChardev *d = MUX_CHARDEV(chr);
 
     /* Fix up the real driver with mux routines */
-    qemu_chr_fe_set_handlers(&d->chr,
-                             mux_chr_can_read,
-                             mux_chr_read,
-                             mux_chr_event,
-                             NULL,
-                             chr,
-                             context, true);
+    qemu_chr_fe_set_handlers_full(&d->chr,
+                                  mux_chr_can_read,
+                                  mux_chr_read,
+                                  mux_chr_event,
+                                  NULL,
+                                  chr,
+                                  context, true, false);
 }
 
 void mux_set_focus(Chardev *chr, int focus)
@@ -367,7 +367,7 @@ static int open_muxes(Chardev *chr)
      * mark mux as OPENED so any new FEs will immediately receive
      * OPENED event
      */
-    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
+    chr->be_open = 1;
 
     return 0;
 }
-- 
2.20.1.519.g8feddda32c

  parent reply	other threads:[~2019-02-07 16:07 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-07 16:05 [Qemu-devel] [PULL 00/18] Chardev patches Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 01/18] io: store reference to thread information in the QIOTask struct Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 02/18] io: add qio_task_wait_thread to join with a background thread Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 03/18] chardev: fix validation of options for QMP created chardevs Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 04/18] chardev: forbid 'reconnect' option with server sockets Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 05/18] chardev: forbid 'wait' option with client sockets Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 06/18] chardev: remove many local variables in qemu_chr_parse_socket Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 07/18] chardev: ensure qemu_chr_parse_compat reports missing driver error Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 08/18] chardev: remove unused 'sioc' variable & cleanup paths Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 09/18] chardev: split tcp_chr_wait_connected into two methods Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 10/18] chardev: split up qmp_chardev_open_socket connection code Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 11/18] chardev: use a state machine for socket connection state Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 12/18] chardev: honour the reconnect setting in tcp_chr_wait_connected Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 13/18] chardev: disallow TLS/telnet/websocket with tcp_chr_wait_connected Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 14/18] chardev: fix race with client connections in tcp_chr_wait_connected Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 15/18] tests: expand coverage of socket chardev test Marc-André Lureau
2019-02-07 16:06 ` [Qemu-devel] [PULL 16/18] chardev: ensure termios is fully initialized Marc-André Lureau
2019-02-07 16:06 ` Marc-André Lureau [this message]
2019-02-07 16:06 ` [Qemu-devel] [PULL 18/18] tests/test-char: add muxed chardev testing for open/close Marc-André Lureau
2019-02-08 11:44 ` [Qemu-devel] [PULL 00/18] Chardev patches Peter Maydell
2019-02-11 17:03   ` Daniel P. Berrangé
2019-02-11 18:29     ` Daniel P. Berrangé
2019-02-11 16:50 ` Daniel P. Berrangé
2019-02-11 16:54   ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190207160617.1142-18-marcandre.lureau@redhat.com \
    --to=marcandre.lureau@redhat.com \
    --cc=artem.k.pisarenko@gmail.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.