qio: general non-default GMainContext support
v2 cover qio: general non-default GMainContext support
This is another preparation work for monitor OOB seires.
V1: http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg06972.html
V2 rewrote the bottom half of the code. The first 8 patches are mostly the same, but I rewrote the last patches to solve both TLS and reconnect use cases by introducing a machine_done hook for chardevs in general. So if I copy the problems:
- migration
- incoming side: still always running on main context, while we need to be able to run some command in OOB thread [1]
- tcp chardev (non-tcp chardevs should all support non-NULL context now)
- server listening mode: QIO net listener used [2]
- TELNET session: an isolated GSource used (tcp_chr_telnet_init) [3]
- when "reconnect=N" is used, QIO threaded task is used [4]
- TLS session: QIO tls handshake is used (tcp_chr_tls_init) [5]
Problem [1-3] are still fixed in the old way, but [4-5] now are fixed by using the new machine_done notifier.
I'll still try to provide a changelog beside the big change mentioned:
v2:
- collect r-bs
- qio_channel_add_watch_full() should still return the same thing as the old one, and introduced qio_channel_add_watch_full() to return a GSource pointer. [Dan]
- Fix commit message on RDMA. It's using QIO, but still, I am not touching it. [Dan]
- use qio_net_listener_set_client_func_full() directly, and avoid introducing new API. [Dan]
Please review. Thanks.
Peter Xu (15):
chardev: fix leak in tcp_chr_telnet_init_io()
qio: rename qio_task_thread_result
qio: introduce qio_channel_add_watch_{full|source}
migration: let incoming side use thread context
qio: refactor net listener source operations
qio: store gsources for net listeners qio/chardev: update net listener gcontext
chardev: allow telnet gsource to switch gcontext
qio: non-default context for threaded qtask
qio: non-default context for async conn
qio: non-default context for TLS handshake
chardev: introduce chr_machine_done hook
char: use chardev's gcontext for async connect
chardev: tcp: postpone async connection setup
chardev: tcp: postpone TLS work until machine done
chardev/char-mux.c | 29 ++++++++++ chardev/char-socket.c | 124 ++++++++++++++++++++++++++++++++--------- chardev/char.c | 43 ++++++-------- include/chardev/char.h | 2 + include/io/channel-socket.h | 4 +- include/io/channel-tls.h | 17 ++++++ include/io/channel.h | 44 +++++++++++++++ include/io/net-listener.h | 21 ++++++- include/io/task.h | 6 +- io/channel-socket.c | 12 ++-- io/channel-tls.c | 51 ++++++++++++----- io/channel.c | 40 +++++++++++-- io/dns-resolver.c | 3 +- io/net-listener.c | 112 +++++++++++++++++++++---------------- io/task.c | 22 +++++++- migration/exec.c | 9 ++- migration/fd.c | 9 ++- migration/socket.c | 13 +++-- tests/test-io-channel-socket.c | 2 +- tests/test-io-task.c | 2 + 20 files changed, 415 insertions(+), 150 deletions(-)
Signature · 1 line
2.14.3
PATCH v2 1/15 chardev: fix leak in tcp_chr_telnet_init_io()
Need to free TCPChardevTelnetInit when session established.
Since at it, switch to use G_SOURCE_* macros.
--- chardev/char-socket.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
chardev/char-socket.c +7 -3
@@ -591,19 +591,23 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, ret =0 ; }else {tcp_chr_disconnect (init->chr); -return FALSE; + goto end; } } init->buflen -= ret;if (init->buflen ==0 ) {tcp_chr_connect (init->chr); -return FALSE; + goto end; }memmove (init->buf, init->buf + ret, init->buflen); -return TRUE; +return G_SOURCE_CONTINUE ; + +end: +g_free (init); +return G_SOURCE_REMOVE ; }static void tcp_chr_telnet_init (Chardev *chr)
Signature · 1 line
2.14.3
Paolo Bonzini
AppliedRe: [Qemu-devel] [PATCH v2 01/15] chardev: fix leak in tcp_chr_telnet_init_io()
Quoted 32 lines · Peter Xu
Need to free TCPChardevTelnetInit when session established.
Since at it, switch to use G_SOURCE_* macros.
Reviewed-by Daniel P. Berrange <[email protected]>Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)chardev/char-socket.c +2
-2@@ -591,19 +591,23 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, ret =0 ; }else {tcp_chr_disconnect (init->chr); -return FALSE; + goto end; } } init->buflen -= ret;if (init->buflen ==0 ) {tcp_chr_connect (init->chr); -return FALSE; + goto end; }memmove (init->buf, init->buf + ret, init->buflen);
chardev/char-socket.c static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, · line 613
Quoted 10 lines
chardev/char-socket.c +5
-1-return TRUE; +return G_SOURCE_CONTINUE ; + +end: +g_free (init); +return G_SOURCE_REMOVE ; }static void tcp_chr_telnet_init (Chardev *chr)
Queued, thanks (but it's okay if you post it again in v3, because I'm not sure I'll be able to send a pull request tomorrow).
Paolo
Re: [Qemu-devel] [PATCH v2 01/15] chardev: fix leak in tcp_chr_telnet_init_io()
Quoted 41 lines · Paolo Bonzini
Quoted 40 lines · Peter Xu
Need to free TCPChardevTelnetInit when session established.
Since at it, switch to use G_SOURCE_* macros.
Reviewed-by Daniel P. Berrange <[email protected]>Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)chardev/char-socket.c +7
-3@@ -591,19 +591,23 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, ret =0 ; }else {tcp_chr_disconnect (init->chr); -return FALSE; + goto end; } } init->buflen -= ret;if (init->buflen ==0 ) {tcp_chr_connect (init->chr); -return FALSE; + goto end; }memmove (init->buf, init->buf + ret, init->buflen); -return TRUE; +return G_SOURCE_CONTINUE ; + +end: +g_free (init); +return G_SOURCE_REMOVE ; }
Quoted 5 lines
chardev/char-socket.c static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, · line 613
Quoted 2 lines
chardev/char-socket.c +0
-0static void tcp_chr_telnet_init (Chardev *chr)Queued, thanks (but it's okay if you post it again in v3, because I'm not sure I'll be able to send a pull request tomorrow).
Sure, thanks.
I believe this is an equivalent "r-b" if I repost. :)
Signature · 1 line
Peter Xu
PATCH v2 2/15 qio: rename qio_task_thread_result
In reply to Peter XuIt is strange that it was called gio_task_thread_result. Rename it to follow the naming rule of the file.
--- io/task.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
io/task.c +2 -2
@@ -80,7 +80,7 @@ struct QIOTaskThreadData { }; -static gboolean gio_task_thread_result (gpointer opaque) +static gboolean qio_task_thread_result (gpointer opaque) {struct QIOTaskThreadData *data = opaque;
@@ -110,7 +110,7 @@ static gpointer qio_task_thread_worker(gpointer opaque)* the worker results */ trace_qio_task_thread_exit (data->task); -g_idle_add (gio_task_thread_result, data); +g_idle_add (qio_task_thread_result, data);return NULL ; }
Signature · 1 line
2.14.3
PATCH v2 3/15 qio: introduce qio_channel_add_watch_{full|source}
In reply to Peter XuFirstly, introduce an internal qio_channel_add_watch_full(), which enhances qio_channel_add_watch() that context can be specified.
Then add a new API wrapper qio_channel_add_watch_source() to return a GSource pointer rather than a tag ID.
Note that the _source() call will keep a reference of GSource so that callers need to unref them explicitly when finished using the GSource.
--- include/io/channel.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ io/channel.c | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 6 deletions(-)
include/io/channel.h +44 -0
@@ -648,6 +648,50 @@ guint qio_channel_add_watch(QIOChannel *ioc,gpointer user_data, GDestroyNotify notify); +/** +* qio_channel_add_watch_full: +* @ioc: the channel object +* @condition: the I/O condition to monitor +* @func: callback to invoke when the source becomes ready +* @user_data: opaque data to pass to @func +* @notify: callback to free @user_data +* @context: the context to run the watch source +* +* Similar as qio_channel_add_watch(), but allows to specify context +* to run the watch source. +* +* Returns: the source ID +*/ +guint qio_channel_add_watch_full (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context); + +/** +* qio_channel_add_watch_source: +* @ioc: the channel object +* @condition: the I/O condition to monitor +* @func: callback to invoke when the source becomes ready +* @user_data: opaque data to pass to @func +* @notify: callback to free @user_data +* @context: gcontext to bind the source to +* +* Similar as qio_channel_add_watch(), but allows to specify context +* to run the watch source, meanwhile return the GSource object +* instead of tag ID, with the GSource referenced already. +* +* Note: callers is responsible to unref the source when not needed. +* +* Returns: the source pointer +*/ +GSource *qio_channel_add_watch_source (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context);/** * qio_channel_attach_aio_context:
io/channel.c +34 -6
@@ -299,11 +299,12 @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc, klass->io_set_aio_fd_handler (ioc, ctx, io_read, io_write, opaque); } -guint qio_channel_add_watch (QIOChannel *ioc, -GIOCondition condition, -QIOChannelFunc func, -gpointer user_data, -GDestroyNotify notify) +guint qio_channel_add_watch_full (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context) {GSource *source;guint id;
@@ -312,12 +313,39 @@ guint qio_channel_add_watch(QIOChannel *ioc,g_source_set_callback (source, (GSourceFunc )func, user_data, notify); - id =g_source_attach (source,NULL ); + id =g_source_attach (source, context);g_source_unref (source);return id; } +guint qio_channel_add_watch (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify) +{ +return qio_channel_add_watch_full (ioc, condition, func, + user_data, notify,NULL ); +} + +GSource *qio_channel_add_watch_source (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context) +{ +GSource *source; +guint id; + + id =qio_channel_add_watch_full (ioc, condition, func, + user_data, notify, context); + source =g_main_context_find_source_by_id (context, id); +g_source_ref (source); +return source; +} + int qio_channel_shutdown(QIOChannel *ioc, QIOChannelShutdown how,
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 03/15] qio: introduce qio_channel_add_watch_{full|source}
Quoted 6 lines · Peter Xu
Firstly, introduce an internal
qio_channel_add_watch_full(), which enhancesqio_channel_add_watch()that context can be specified.Then add a new API wrapper
qio_channel_add_watch_source()to return a GSource pointer rather than a tag ID.
Quoted 8 lines
Note that the
_source()call will keep a reference of GSource so that callers need to unref them explicitly when finished using the GSource.Signed-off-by Peter Xu <[email protected]>--- include/io/channel.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ io/channel.c | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 6 deletions(-)
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 03/15] qio: introduce qio_channel_add_watch_{full|source}
In reply to Peter XuQuoted 17 lines · Peter Xu
+ *
qio_channel_add_watch_source:
+ * @ioc: the channel object
+ * @condition: the I/O condition to monitor
+ * @func: callback to invoke when the source becomes ready
+ * @user_data: opaque data to pass to @func
+ * @notify: callback to free @user_data
+ * @context: gcontext to bind the source to
+ *
+ * Similar asqio_channel_add_watch(), but allows to specify context
+ * to run the watch source, meanwhile return the GSource object
+ * instead of tag ID, with the GSource referenced already.
+ *
+ * Note: callers is responsible to unref the source when not needed.
+ *
+ * Returns: the source pointer
+ */
include/io/channel.h guint qio_channel_add_watch(QIOChannel *ioc, · line 694
Quoted 6 lines
include/io/channel.h +6
-0+GSource *qio_channel_add_watch_source (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context);
Just a small thing, this is a bit inconsistent with the rest of the GSource API, where the g_source_attach is usually left to the caller when a function returns GSource *.
You might therefore name it instead qio_channel_create_watch, for consistency with g_io_{add,create}_watch, and remove the "context" argument.
(Not making it perfectly the same API is okay, for example in practice all callers would use g_source_set_callback so it's okay IMO to add the three arguments func/user_data/notify. However, inconsistency on g_source_add is more subtle).
Thanks,
Paolo
Re: [Qemu-devel] [PATCH v2 03/15] qio: introduce qio_channel_add_watch_{full|source}
Quoted 25 lines · Paolo Bonzini
Quoted 17 lines · Peter Xu
+ *
qio_channel_add_watch_source:
+ * @ioc: the channel object
+ * @condition: the I/O condition to monitor
+ * @func: callback to invoke when the source becomes ready
+ * @user_data: opaque data to pass to @func
+ * @notify: callback to free @user_data
+ * @context: gcontext to bind the source to
+ *
+ * Similar asqio_channel_add_watch(), but allows to specify context
+ * to run the watch source, meanwhile return the GSource object
+ * instead of tag ID, with the GSource referenced already.
+ *
+ * Note: callers is responsible to unref the source when not needed.
+ *
+ * Returns: the source pointer
+ */include/io/channel.h guint qio_channel_add_watch(QIOChannel *ioc, · line 694
Quoted 6 lines
include/io/channel.h +6
-0+GSource *qio_channel_add_watch_source (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context);
Quoted 6 lines
Just a small thing, this is a bit inconsistent with the rest of the GSource API, where the
g_source_attachis usually left to the caller when a function returns GSource *.You might therefore name it instead
qio_channel_create_watch, for consistency with g_io_{add,create}_watch, and remove the "context" argument.
Looks like there is already a qio_channel_create_watch() (io/channel.c).
How about qio_channel_create_watch_attached()? Or... anything better?
Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 03/15] qio: introduce qio_channel_add_watch_{full|source}
Quoted 30 lines · Peter Xu
Quoted 29 lines · Paolo Bonzini
Quoted 17 lines · Peter Xu
+ *
qio_channel_add_watch_source:
+ * @ioc: the channel object
+ * @condition: the I/O condition to monitor
+ * @func: callback to invoke when the source becomes ready
+ * @user_data: opaque data to pass to @func
+ * @notify: callback to free @user_data
+ * @context: gcontext to bind the source to
+ *
+ * Similar asqio_channel_add_watch(), but allows to specify context
+ * to run the watch source, meanwhile return the GSource object
+ * instead of tag ID, with the GSource referenced already.
+ *
+ * Note: callers is responsible to unref the source when not needed.
+ *
+ * Returns: the source pointer
+ */include/io/channel.h guint qio_channel_add_watch(QIOChannel *ioc, · line 694
Quoted 6 lines
include/io/channel.h +6
-0+GSource *qio_channel_add_watch_source (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context);Just a small thing, this is a bit inconsistent with the rest of the GSource API, where the
g_source_attachis usually left to the caller when a function returns GSource *.
Quoted 6 lines
Quoted 2 lines
You might therefore name it instead
qio_channel_create_watch, for consistency with g_io_{add,create}_watch, and remove the "context" argument.Looks like there is already a
qio_channel_create_watch()(io/channel.c).How about
qio_channel_create_watch_attached()? Or... anything better?
I would add the g_source_set_callback call (and arguments) to qio_channel_create_watch and leave the g_source_attach to the caller.
Paolo
Re: [Qemu-devel] [PATCH v2 03/15] qio: introduce qio_channel_add_watch_{full|source}
In reply to Paolo BonziniQuoted 25 lines · Paolo Bonzini
Quoted 17 lines · Peter Xu
+ *
qio_channel_add_watch_source:
+ * @ioc: the channel object
+ * @condition: the I/O condition to monitor
+ * @func: callback to invoke when the source becomes ready
+ * @user_data: opaque data to pass to @func
+ * @notify: callback to free @user_data
+ * @context: gcontext to bind the source to
+ *
+ * Similar asqio_channel_add_watch(), but allows to specify context
+ * to run the watch source, meanwhile return the GSource object
+ * instead of tag ID, with the GSource referenced already.
+ *
+ * Note: callers is responsible to unref the source when not needed.
+ *
+ * Returns: the source pointer
+ */include/io/channel.h guint qio_channel_add_watch(QIOChannel *ioc, · line 694
Quoted 6 lines
include/io/channel.h +6
-0+GSource *qio_channel_add_watch_source (QIOChannel *ioc, +GIOCondition condition, +QIOChannelFunc func, +gpointer user_data, +GDestroyNotify notify, +GMainContext *context);
Quoted 3 lines
Just a small thing, this is a bit inconsistent with the rest of the GSource API, where the
g_source_attachis usually left to the caller when a function returns GSource *.
The APIs which return a GSource in glib typically don't even set the callback function - we already cover that scenario with the qio_channel_create_watch APIs.
GLib doesn't typically have APIs which return a GSource after the mix of creating the watch, setting callback & attaching to context. They all just return the watch ID value.
So I think this proposal is ok as it is as there's no real precedence.
Alternatively we could simply do without this API entirely. It is trivial enough for the code that needs a GSource to get iuse the normal qio_channel_add_watch|watch_full APIs, and then lookup the GSource themselves - only one extra line of code in the callers.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 03/15] qio: introduce qio_channel_add_watch_{full|source}
Quoted 9 lines · Daniel P. Berrangé
Quoted 3 lines
Just a small thing, this is a bit inconsistent with the rest of the GSource API, where the
g_source_attachis usually left to the caller when a function returns GSource *.The APIs which return a GSource in glib typically don't even set the callback function - we already cover that scenario with the
qio_channel_create_watchAPIs.GLib doesn't typically have APIs which return a GSource after the mix of creating the watch, setting callback & attaching to context.
True, on the other hand it's annoying for qio_channel_create_watch because of the function pointer case. So I suggested a mix of creating the watch and setting the callback.
Having a function that takes a GMainContext and returns a tag is fine, too.
Paolo
Quoted 8 lines
They all just return the watch ID value.
So I think this proposal is ok as it is as there's no real precedence.
Alternatively we could simply do without this API entirely. It is trivial enough for the code that needs a GSource to get iuse the normal qio_channel_add_watch|watch_full APIs, and then lookup the GSource themselves - only one extra line of code in the callers.
PATCH v2 4/15 migration: let incoming side use thread context
In reply to Peter XuThe old incoming migration is running in main thread and default gcontext. With the new qio_channel_add_watch_full() we can now let it run in the thread's own gcontext (if there is one).
Currently this patch does nothing alone. But when any of the incoming migration is run in another iothread (e.g., the upcoming migrate-recover command), this patch will bind the incoming logic to the iothread instead of the main thread (which may already get page faulted and hanged).
RDMA is not considered for now since it's not even using the QIO watch framework at all.
--- migration/exec.c | 9 ++++----- migration/fd.c | 9 ++++----- migration/socket.c | 10 +++++----- 3 files changed, 13 insertions(+), 15 deletions(-)
migration/exec.c +4 -5
@@ -65,9 +65,8 @@ void exec_start_incoming_migration(const char *command, Error **errp) }qio_channel_set_name (ioc,"migration-exec-incoming" ); -qio_channel_add_watch (ioc, -G_IO_IN , - exec_accept_incoming_migration, -NULL , -NULL ); +qio_channel_add_watch_full (ioc,G_IO_IN , + exec_accept_incoming_migration, +NULL ,NULL , +g_main_context_get_thread_default ()); }
migration/fd.c +4 -5
@@ -66,9 +66,8 @@ void fd_start_incoming_migration(const char *infd, Error **errp) }qio_channel_set_name (QIO_CHANNEL (ioc),"migration-fd-incoming" ); -qio_channel_add_watch (ioc, -G_IO_IN , - fd_accept_incoming_migration, -NULL , -NULL ); +qio_channel_add_watch_full (ioc,G_IO_IN , + fd_accept_incoming_migration, +NULL ,NULL , +g_main_context_get_thread_default ()); }
migration/socket.c +5 -5
@@ -173,11 +173,11 @@ static void socket_start_incoming_migration(SocketAddress *saddr,return ; } -qio_channel_add_watch (QIO_CHANNEL (listen_ioc), -G_IO_IN , - socket_accept_incoming_migration, - listen_ioc, - (GDestroyNotify )object_unref); +qio_channel_add_watch_full (QIO_CHANNEL (listen_ioc),G_IO_IN , + socket_accept_incoming_migration, + listen_ioc, + (GDestroyNotify )object_unref, +g_main_context_get_thread_default ()); }void tcp_start_incoming_migration (const char *host_port,Error **errp)
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 04/15] migration: let incoming side use thread context
Quoted 17 lines · Peter Xu
The old incoming migration is running in main thread and default gcontext. With the new
qio_channel_add_watch_full()we can now let it run in the thread's own gcontext (if there is one).Currently this patch does nothing alone. But when any of the incoming migration is run in another iothread (e.g., the upcoming migrate-recover command), this patch will bind the incoming logic to the iothread instead of the main thread (which may already get page faulted and hanged).
RDMA is not considered for now since it's not even using the QIO watch framework at all.
CC Juan Quintela <[email protected]>CC Dr. David Alan Gilbert <[email protected]>CC Laurent Vivier <[email protected]>Signed-off-by Peter Xu <[email protected]>
Quoted 5 lines
--- migration/exec.c | 9 ++++----- migration/fd.c | 9 ++++----- migration/socket.c | 10 +++++----- 3 files changed, 13 insertions(+), 15 deletions(-)
This should probably just be in a separate series, since it does nothing on its own, and nothing following in this series touches migration at all.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 04/15] migration: let incoming side use thread context
Quoted 24 lines · Daniel P. Berrangé
Quoted 17 lines · Peter Xu
The old incoming migration is running in main thread and default gcontext. With the new
qio_channel_add_watch_full()we can now let it run in the thread's own gcontext (if there is one).Currently this patch does nothing alone. But when any of the incoming migration is run in another iothread (e.g., the upcoming migrate-recover command), this patch will bind the incoming logic to the iothread instead of the main thread (which may already get page faulted and hanged).
RDMA is not considered for now since it's not even using the QIO watch framework at all.
CC Juan Quintela <[email protected]>CC Dr. David Alan Gilbert <[email protected]>CC Laurent Vivier <[email protected]>Signed-off-by Peter Xu <[email protected]>Quoted 5 lines
--- migration/exec.c | 9 ++++----- migration/fd.c | 9 ++++----- migration/socket.c | 10 +++++----- 3 files changed, 13 insertions(+), 15 deletions(-)
Quoted 2 lines
This should probably just be in a separate series, since it does nothing on its own, and nothing following in this series touches migration at all.
It was trying to solve all problems related to QIO+context, and migration is just one user of it. But sure I can postpone this patch to the postcopy recovery series.
Thanks,
Signature · 1 line
Peter Xu
PATCH v2 5/15 qio: refactor net listener source operations
In reply to Peter XuThree functions are abstracted from the old code:
- qio_net_listener_source_add(): create one source for listener
- qio_net_listener_sources_clear(): unset existing net lister sources
- qio_net_listener_sources_update(): setup all sources for listener
Use them where possible.
--- io/net-listener.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-)
io/net-listener.c +41 -41
@@ -106,6 +106,39 @@ int qio_net_listener_open_sync(QIONetListener *listener, } } +static guint qio_net_listener_source_add (QIONetListener *listener, +QIOChannelSocket *sioc) +{ +return qio_channel_add_watch (QIO_CHANNEL (sioc),G_IO_IN , + qio_net_listener_channel_func, + listener, (GDestroyNotify )object_unref); +} + +static void qio_net_listener_sources_clear (QIONetListener *listener) +{ +size_t i; + +for (i =0 ; i < listener->nsioc; i++) { +if (listener->io_tag[i]) { +g_source_remove (listener->io_tag[i]); + listener->io_tag[i] =0 ; + } + } +} + +static void qio_net_listener_sources_update (QIONetListener *listener) +{ +size_t i; + +if (listener->io_func !=NULL ) { +for (i =0 ; i < listener->nsioc; i++) { +assert (listener->io_tag[i] ==0 ); +object_ref (OBJECT (listener)); + listener->io_tag[i] =qio_net_listener_source_add ( + listener, listener->sioc[i]); + } + } +}void qio_net_listener_add (QIONetListener *listener,QIOChannelSocket *sioc)
@@ -127,10 +160,8 @@ void qio_net_listener_add(QIONetListener *listener,if (listener->io_func !=NULL ) {object_ref (OBJECT (listener)); - listener->io_tag[listener->nsioc] =qio_channel_add_watch ( -QIO_CHANNEL (listener->sioc[listener->nsioc]),G_IO_IN , - qio_net_listener_channel_func, - listener, (GDestroyNotify )object_unref); + listener->io_tag[listener->nsioc] =qio_net_listener_source_add ( + listener, listener->sioc[listener->nsioc]); } listener->nsioc++;
@@ -142,8 +173,6 @@ void qio_net_listener_set_client_func(QIONetListener *listener, gpointer data, GDestroyNotify notify) { - size_t i; - if (listener->io_notify) { listener->io_notify (listener->io_data); }
@@ -151,22 +180,8 @@ void qio_net_listener_set_client_func(QIONetListener *listener, listener->io_data = data; listener->io_notify = notify; -for (i =0 ; i < listener->nsioc; i++) { -if (listener->io_tag[i]) { -g_source_remove (listener->io_tag[i]); - listener->io_tag[i] =0 ; - } - } - -if (listener->io_func !=NULL ) { -for (i =0 ; i < listener->nsioc; i++) { -object_ref (OBJECT (listener)); - listener->io_tag[i] =qio_channel_add_watch ( -QIO_CHANNEL (listener->sioc[i]),G_IO_IN , - qio_net_listener_channel_func, - listener, (GDestroyNotify )object_unref); - } - } +qio_net_listener_sources_clear (listener); +qio_net_listener_sources_update (listener); }
@@ -210,12 +225,7 @@ QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) };size_t i; -for (i =0 ; i < listener->nsioc; i++) { -if (listener->io_tag[i]) { -g_source_remove (listener->io_tag[i]); - listener->io_tag[i] =0 ; - } - } +qio_net_listener_sources_clear (listener); sources = g_new0(GSource *, listener->nsioc);for (i =0 ; i < listener->nsioc; i++) {
@@ -238,15 +248,7 @@ QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener)g_main_loop_unref (loop);g_main_context_unref (ctxt); -if (listener->io_func !=NULL ) { -for (i =0 ; i < listener->nsioc; i++) { -object_ref (OBJECT (listener)); - listener->io_tag[i] =qio_channel_add_watch ( -QIO_CHANNEL (listener->sioc[i]),G_IO_IN , - qio_net_listener_channel_func, - listener, (GDestroyNotify )object_unref); - } - } +qio_net_listener_sources_update (listener);return data.sioc; }
@@ -259,11 +261,9 @@ void qio_net_listener_disconnect(QIONetListener *listener)return ; } +qio_net_listener_sources_clear (listener); +for (i =0 ; i < listener->nsioc; i++) { -if (listener->io_tag[i]) { -g_source_remove (listener->io_tag[i]); - listener->io_tag[i] =0 ; - }qio_channel_close (QIO_CHANNEL (listener->sioc[i]),NULL ); } listener->connected = false;
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 05/15] qio: refactor net listener source operations
Quoted 6 lines · Peter Xu
Three functions are abstracted from the old code:
-
qio_net_listener_source_add(): create one source for listener
-qio_net_listener_sources_clear(): unset existing net lister sources
-qio_net_listener_sources_update(): setup all sources for listener
Quoted 6 lines
Use them where possible.
Signed-off-by Peter Xu <[email protected]>--- io/net-listener.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-)
This patch can be dropped since nothing else in the series now depends on it.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 05/15] qio: refactor net listener source operations
Quoted 9 lines · Daniel P. Berrangé
Quoted 8 lines · Peter Xu
Three functions are abstracted from the old code:
-
qio_net_listener_source_add(): create one source for listener
-qio_net_listener_sources_clear(): unset existing net lister sources
-qio_net_listener_sources_update(): setup all sources for listenerUse them where possible.
Quoted 7 lines
Quoted 4 lines
Signed-off-by Peter Xu <[email protected]>--- io/net-listener.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-)This patch can be dropped since nothing else in the series now depends on it.
Do you think it's still acceptable even as a cleanup? Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 05/15] qio: refactor net listener source operations
Quoted 15 lines · Peter Xu
Quoted 14 lines · Daniel P. Berrangé
Quoted 12 lines · Peter Xu
Three functions are abstracted from the old code:
-
qio_net_listener_source_add(): create one source for listener
-qio_net_listener_sources_clear(): unset existing net lister sources
-qio_net_listener_sources_update(): setup all sources for listenerUse them where possible.
Signed-off-by Peter Xu <[email protected]>--- io/net-listener.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-)
Quoted 4 lines
Quoted 2 lines
This patch can be dropped since nothing else in the series now depends on it.
Do you think it's still acceptable even as a cleanup? Thanks,
Ah, and patch 6 actually depends on it (currently). For sure I can do some rebase work to drop current one, but IMHO I would prefer to keep both there. Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 05/15] qio: refactor net listener source operations
In reply to Peter XuQuoted 15 lines · Peter Xu
Quoted 14 lines · Daniel P. Berrangé
Quoted 12 lines · Peter Xu
Three functions are abstracted from the old code:
-
qio_net_listener_source_add(): create one source for listener
-qio_net_listener_sources_clear(): unset existing net lister sources
-qio_net_listener_sources_update(): setup all sources for listenerUse them where possible.
Signed-off-by Peter Xu <[email protected]>--- io/net-listener.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-)
Quoted 4 lines
Quoted 2 lines
This patch can be dropped since nothing else in the series now depends on it.
Do you think it's still acceptable even as a cleanup? Thanks,
I don't think it really adds value over what's there already.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 05/15] qio: refactor net listener source operations
Quoted 16 lines · Daniel P. Berrangé
Quoted 15 lines · Peter Xu
Quoted 14 lines · Daniel P. Berrangé
Quoted 12 lines · Peter Xu
Three functions are abstracted from the old code:
-
qio_net_listener_source_add(): create one source for listener
-qio_net_listener_sources_clear(): unset existing net lister sources
-qio_net_listener_sources_update(): setup all sources for listenerUse them where possible.
Signed-off-by Peter Xu <[email protected]>--- io/net-listener.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-)
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
This patch can be dropped since nothing else in the series now depends on it.
Do you think it's still acceptable even as a cleanup? Thanks,
I don't think it really adds value over what's there already.
I'll drop it. Thanks.
Signature · 1 line
Peter Xu
PATCH v2 6/15 qio: store gsources for net listeners
In reply to Peter XuOriginally we were storing the GSources tag IDs. That'll be not enough if we are going to support non-default gcontext for QIO code. Switch to GSources without changing anything real. Now we still always pass in NULL, which means the default gcontext.
--- include/io/net-listener.h | 21 ++++++++++++++-- io/net-listener.c | 62 +++++++++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 25 deletions(-)
include/io/net-listener.h +19 -2
@@ -53,7 +53,7 @@ struct QIONetListener {char *name;QIOChannelSocket **sioc; -gulong *io_tag; +GSource **io_source;size_t nsioc;bool connected;
@@ -120,17 +120,34 @@ void qio_net_listener_add(QIONetListener *listener, QIOChannelSocket *sioc);/** -* qio_net_listener_set_client_func: +* qio_net_listener_set_client_func_full: * @listener: the network listener object * @func: the callback function * @data: opaque data to pass to @func * @notify: callback to free @data +* @context: the context that the sources will be bound to * * Register @func to be invoked whenever a new client * connects to the listener. @func will be invoked * passing in the QIOChannelSocket instance for the * client. */ +void qio_net_listener_set_client_func_full (QIONetListener *listener, +QIONetListenerClientFunc func, +gpointer data, +GDestroyNotify notify, +GMainContext *context); + +/** +* qio_net_listener_set_client_func: +* @listener: the network listener object +* @func: the callback function +* @data: opaque data to pass to @func +* @notify: callback to free @data +* +* Wrapper of qio_net_listener_set_client_func_full(), only that the +* sources will always be bound to default main context. +*/ void qio_net_listener_set_client_func(QIONetListener *listener, QIONetListenerClientFunc func, gpointer data,
io/net-listener.c +39 -23
124 lines not on this page · raw message
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 06/15] qio: store gsources for net listeners
Quoted 10 lines · Peter Xu
Originally we were storing the GSources tag IDs. That'll be not enough if we are going to support non-default gcontext for QIO code. Switch to GSources without changing anything real. Now we still always pass in NULL, which means the default gcontext.
Signed-off-by Peter Xu <[email protected]>--- include/io/net-listener.h | 21 ++++++++++++++-- io/net-listener.c | 62 +++++++++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 25 deletions(-)
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 06/15] qio: store gsources for net listeners
In reply to Peter XuQuoted 25 lines · Peter Xu
Originally we were storing the GSources tag IDs. That'll be not enough if we are going to support non-default gcontext for QIO code. Switch to GSources without changing anything real. Now we still always pass in NULL, which means the default gcontext.
Signed-off-by Peter Xu <[email protected]>--- include/io/net-listener.h | 21 ++++++++++++++-- io/net-listener.c | 62 +++++++++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 25 deletions(-)include/io/net-listener.h +1
-1@@ -53,7 +53,7 @@ struct QIONetListener {char *name;QIOChannelSocket **sioc; -gulong *io_tag; +GSource **io_source;size_t nsioc;bool connected;
include/io/net-listener.h void qio_net_listener_add(QIONetListener *listener, · line 128
Quoted 10 lines
include/io/net-listener.h +2
-1@@ -120,17 +120,34 @@ void qio_net_listener_add(QIONetListener *listener, QIOChannelSocket *sioc);/** -* qio_net_listener_set_client_func: +* qio_net_listener_set_client_func_full: * @listener: the network listener object * @func: the callback function * @data: opaque data to pass to @func * @notify: callback to free @data +* @context: the context that the sources will be bound to
Please add a note like "if %NULL, the default context will be used".
Paolo
Re: [Qemu-devel] [PATCH v2 06/15] qio: store gsources for net listeners
Quoted 28 lines · Paolo Bonzini
Quoted 27 lines · Peter Xu
Originally we were storing the GSources tag IDs. That'll be not enough if we are going to support non-default gcontext for QIO code. Switch to GSources without changing anything real. Now we still always pass in NULL, which means the default gcontext.
Signed-off-by Peter Xu <[email protected]>--- include/io/net-listener.h | 21 ++++++++++++++-- io/net-listener.c | 62 +++++++++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 25 deletions(-)include/io/net-listener.h +1
-1@@ -53,7 +53,7 @@ struct QIONetListener {char *name;QIOChannelSocket **sioc; -gulong *io_tag; +GSource **io_source;size_t nsioc;bool connected;@@ -120,17 +120,34 @@ void qio_net_listener_add(QIONetListener *listener, QIOChannelSocket *sioc);
Quoted 10 lines
include/io/net-listener.h void qio_net_listener_add(QIONetListener *listener, · line 128
Quoted 8 lines
include/io/net-listener.h +2
-1/** -* qio_net_listener_set_client_func: +* qio_net_listener_set_client_func_full: * @listener: the network listener object * @func: the callback function * @data: opaque data to pass to @func * @notify: callback to free @data +* @context: the context that the sources will be bound to Please add a note like "if %NULL, the default context will be used".
Will do. Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 06/15] qio: store gsources for net listeners
In reply to Paolo BonziniQuoted 28 lines · Paolo Bonzini
Quoted 27 lines · Peter Xu
Originally we were storing the GSources tag IDs. That'll be not enough if we are going to support non-default gcontext for QIO code. Switch to GSources without changing anything real. Now we still always pass in NULL, which means the default gcontext.
Signed-off-by Peter Xu <[email protected]>--- include/io/net-listener.h | 21 ++++++++++++++-- io/net-listener.c | 62 +++++++++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 25 deletions(-)include/io/net-listener.h +1
-1@@ -53,7 +53,7 @@ struct QIONetListener {char *name;QIOChannelSocket **sioc; -gulong *io_tag; +GSource **io_source;size_t nsioc;bool connected;@@ -120,17 +120,34 @@ void qio_net_listener_add(QIONetListener *listener, QIOChannelSocket *sioc);
Quoted 10 lines
include/io/net-listener.h void qio_net_listener_add(QIONetListener *listener, · line 128
Quoted 8 lines
include/io/net-listener.h +2
-1/** -* qio_net_listener_set_client_func: +* qio_net_listener_set_client_func_full: * @listener: the network listener object * @func: the callback function * @data: opaque data to pass to @func * @notify: callback to free @data +* @context: the context that the sources will be bound to Please add a note like "if %NULL, the default context will be used".
Fixed this one too (and for both patches, I kept Dan's r-b). Thanks,
Signature · 1 line
Peter Xu
PATCH v2 7/15 qio/chardev: update net listener gcontext
In reply to Peter XuTCP chardevs can be using QIO network listeners working in the background when in listening mode. However the network listeners are always running in main context. This can race with chardevs that are running in non-main contexts.
To solve this, we need to re-setup the net listeners in tcp_chr_update_read_handler() with the newly cached gcontext.
Since at it, generalize a tcp_chr_net_listener_setup() helper function and clean up the old code a bit.
--- chardev/char-socket.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-)
chardev/char-socket.c +26 -6
@@ -410,6 +410,19 @@ static void update_disconnected_filename(SocketChardev *s) s->is_listen, s->is_telnet); } +/* Set enable=true to start net listeners, false to stop them. */ +static void tcp_chr_net_listener_setup (SocketChardev *s,bool enable) +{ +Chardev *chr =CHARDEV (s); + +/* Net listeners' context will follow the Chardev's. */ +qio_net_listener_set_client_func_full (s->listener, + enable ? tcp_chr_accept :NULL , + enable ? chr :NULL , +NULL , + chr->gcontext); +} +/* NB may be called even if tcp_chr_connect has not been * reached, due to TLS or telnet initialization failure, * so can *not* assume s->connected == true
@@ -422,8 +435,7 @@ static void tcp_chr_disconnect(Chardev *chr)tcp_chr_free_connection (chr);if (s->listener) { -qio_net_listener_set_client_func (s->listener, tcp_chr_accept, - chr,NULL ); +tcp_chr_net_listener_setup (s, true); }update_disconnected_filename (s);if (emit_close) {
@@ -559,6 +571,15 @@ static void tcp_chr_update_read_handler(Chardev *chr) {SocketChardev *s =SOCKET_CHARDEV (chr); +if (s->listener) { +/* +* It's possible that chardev context is changed in +* qemu_chr_be_update_read_handlers(). Reset it for QIO net +* listener if there is. +*/ +tcp_chr_net_listener_setup (s, true); + } +if (!s->connected) {return ; }
@@ -742,7 +763,7 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)qio_channel_set_delay (s->ioc, false); }if (s->listener) { -qio_net_listener_set_client_func (s->listener,NULL ,NULL ,NULL ); +tcp_chr_net_listener_setup (s, false); }if (s->tls_creds) {
@@ -823,7 +844,7 @@ static void char_socket_finalize(Object *obj)tcp_chr_reconn_timer_cancel (s);qapi_free_SocketAddress (s->addr);if (s->listener) { -qio_net_listener_set_client_func (s->listener,NULL ,NULL ,NULL ); +tcp_chr_net_listener_setup (s, false);object_unref (OBJECT (s->listener)); }if (s->tls_creds) {
@@ -979,8 +1000,7 @@ static void qmp_chardev_open_socket(Chardev *chr,return ; }if (!s->ioc) { -qio_net_listener_set_client_func (s->listener, tcp_chr_accept, - chr,NULL ); +tcp_chr_net_listener_setup (s, true); } }else if (qemu_chr_wait_connected (chr, errp) <0 ) { goto error;
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 07/15] qio/chardev: update net listener gcontext
Quoted 25 lines · Peter Xu
TCP chardevs can be using QIO network listeners working in the background when in listening mode. However the network listeners are always running in main context. This can race with chardevs that are running in non-main contexts.
To solve this, we need to re-setup the net listeners in
tcp_chr_update_read_handler()with the newly cached gcontext.Since at it, generalize a
tcp_chr_net_listener_setup()helper function and clean up the old code a bit.Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-)chardev/char-socket.c +1
-0@@ -410,6 +410,19 @@ static void update_disconnected_filename(SocketChardev *s) s->is_listen, s->is_telnet); } +/* Set enable=true to start net listeners, false to stop them. */
chardev/char-socket.c static void update_disconnected_filename(SocketChardev *s) · line 423
Quoted 10 lines
chardev/char-socket.c +10
-0+static void tcp_chr_net_listener_setup (SocketChardev *s,bool enable) +{ +Chardev *chr =CHARDEV (s); + +/* Net listeners' context will follow the Chardev's. */ +qio_net_listener_set_client_func_full (s->listener, + enable ? tcp_chr_accept :NULL , + enable ? chr :NULL , +NULL , + chr->gcontext);
I don't think this helper method is really a benefit. In fact I think it makes understanding the code harder, because when you see tcp_chr_net_listener_setup(s, true), you've no idea what 'true' means without going to finding the impl of tcp_chr_net_listener_setup().
Just leave the direct calls to qio_net_listener_set_client_func_full as they are IMHO.
Quoted 62 lines
chardev/char-socket.c +15
-6+} +/* NB may be called even if tcp_chr_connect has not been * reached, due to TLS or telnet initialization failure, * so can *not* assume s->connected == true @@ -422,8 +435,7 @@ static void tcp_chr_disconnect(Chardev *chr)tcp_chr_free_connection (chr);if (s->listener) { -qio_net_listener_set_client_func (s->listener, tcp_chr_accept, - chr,NULL ); +tcp_chr_net_listener_setup (s, true); }update_disconnected_filename (s);if (emit_close) {@@ -559,6 +571,15 @@ static void tcp_chr_update_read_handler(Chardev *chr) {SocketChardev *s =SOCKET_CHARDEV (chr); +if (s->listener) { +/* +* It's possible that chardev context is changed in +* qemu_chr_be_update_read_handlers(). Reset it for QIO net +* listener if there is. +*/ +tcp_chr_net_listener_setup (s, true); + } +if (!s->connected) {return ; }@@ -742,7 +763,7 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)qio_channel_set_delay (s->ioc, false); }if (s->listener) { -qio_net_listener_set_client_func (s->listener,NULL ,NULL ,NULL ); +tcp_chr_net_listener_setup (s, false); }if (s->tls_creds) {@@ -823,7 +844,7 @@ static void char_socket_finalize(Object *obj)tcp_chr_reconn_timer_cancel (s);qapi_free_SocketAddress (s->addr);if (s->listener) { -qio_net_listener_set_client_func (s->listener,NULL ,NULL ,NULL ); +tcp_chr_net_listener_setup (s, false);object_unref (OBJECT (s->listener)); }if (s->tls_creds) {@@ -979,8 +1000,7 @@ static void qmp_chardev_open_socket(Chardev *chr,return ; }if (!s->ioc) { -qio_net_listener_set_client_func (s->listener, tcp_chr_accept, - chr,NULL ); +tcp_chr_net_listener_setup (s, true); } }else if (qemu_chr_wait_connected (chr, errp) <0 ) { goto error;Signature · 1 line
2.14.3
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 07/15] qio/chardev: update net listener gcontext
Quoted 42 lines · Daniel P. Berrangé
Quoted 25 lines · Peter Xu
TCP chardevs can be using QIO network listeners working in the background when in listening mode. However the network listeners are always running in main context. This can race with chardevs that are running in non-main contexts.
To solve this, we need to re-setup the net listeners in
tcp_chr_update_read_handler()with the newly cached gcontext.Since at it, generalize a
tcp_chr_net_listener_setup()helper function and clean up the old code a bit.Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-)chardev/char-socket.c +1
-0@@ -410,6 +410,19 @@ static void update_disconnected_filename(SocketChardev *s) s->is_listen, s->is_telnet); } +/* Set enable=true to start net listeners, false to stop them. */ chardev/char-socket.c static void update_disconnected_filename(SocketChardev *s) · line 423
Quoted 10 lines
chardev/char-socket.c +10
-0+static void tcp_chr_net_listener_setup (SocketChardev *s,bool enable) +{ +Chardev *chr =CHARDEV (s); + +/* Net listeners' context will follow the Chardev's. */ +qio_net_listener_set_client_func_full (s->listener, + enable ? tcp_chr_accept :NULL , + enable ? chr :NULL , +NULL , + chr->gcontext);I don't think this helper method is really a benefit. In fact I think it makes understanding the code harder, because when you see
tcp_chr_net_listener_setup(s, true), you've no idea what 'true' means without going to finding the impl oftcp_chr_net_listener_setup().
Quoted 2 lines
Just leave the direct calls to
qio_net_listener_set_client_func_fullas they are IMHO.
Frankly speaking I was a bit confused when I started to read chardev/qio codes with so many hooks, e.g., when I saw:
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
chr, NULL);I totally have no idea on what happened. I need to go deeper into the net listener code to know that, hmm, it's setting up something to accept connections!
If I can have something like:
tcp_chr_net_listener_setup(s, true);
It may be easier for me to understand that there's something either registered for the listening ports, and I don't need to care about which function will be called when accept happened. Basically it "hides" some logic inside, that's IMHO where functions/macros help.
(Here the naming of function is discussible for sure, along with how
to define the parameters)
I think it may be a flavor issue. In that case, I'm always fine with either way. I assume the previous cleanup patch 5 is similarly a flavor issue too, so I'll follow your final judgement on what you would prefer.
Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 07/15] qio/chardev: update net listener gcontext
Quoted 10 lines · Peter Xu
Frankly speaking I was a bit confused when I started to read chardev/qio codes with so many hooks, e.g., when I saw:
qio_net_listener_set_client_func(s->listener, tcp_chr_accept, chr, NULL);I totally have no idea on what happened. I need to go deeper into the net listener code to know that, hmm, it's setting up something to accept connections!
Quoted 8 lines
If I can have something like:
tcp_chr_net_listener_setup(s, true);It may be easier for me to understand that there's something either registered for the listening ports, and I don't need to care about which function will be called when accept happened. Basically it "hides" some logic inside, that's IMHO where functions/macros help.
I tend to agree with Daniel, but I probably would be convinced if you had a pair of functions tcp_chr_{start,stop}_listen instead of a bool argument.
Paolo
Re: [Qemu-devel] [PATCH v2 07/15] qio/chardev: update net listener gcontext
Quoted 15 lines · Paolo Bonzini
Quoted 14 lines · Peter Xu
Frankly speaking I was a bit confused when I started to read chardev/qio codes with so many hooks, e.g., when I saw:
qio_net_listener_set_client_func(s->listener, tcp_chr_accept, chr, NULL);I totally have no idea on what happened. I need to go deeper into the net listener code to know that, hmm, it's setting up something to accept connections!
If I can have something like:
tcp_chr_net_listener_setup(s, true);
Quoted 8 lines
Quoted 4 lines
It may be easier for me to understand that there's something either registered for the listening ports, and I don't need to care about which function will be called when accept happened. Basically it "hides" some logic inside, that's IMHO where functions/macros help.
I tend to agree with Daniel, but I probably would be convinced if you had a pair of functions tcp_chr_{start,stop}_listen instead of a bool argument.
Thanks Paolo for your suggestion.
Let me just keep the code untouched so that we can be more focused on the topic of the series. I'll try to avoid unecessary clean ups there. Thanks,
Signature · 1 line
Peter Xu
PATCH v2 8/15 chardev: allow telnet gsource to switch gcontext
In reply to Peter XuIt was originally created by qio_channel_add_watch() so it's always assigning the task to main context. Now we use the new API called qio_channel_add_watch_source() so that we get the GSource handle rather than the tag ID.
Meanwhile, caching the gsource in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers.
--- chardev/char-socket.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
chardev/char-socket.c +24 -4
@@ -59,6 +59,7 @@ typedef struct {bool is_listen;bool is_telnet;bool is_tn3270; +GSource *telnet_source;GSource *reconnect_timer;int64_t reconnect_time;
@@ -69,6 +70,7 @@ typedef struct { OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)static gboolean socket_reconnect_timeout (gpointer opaque); +static void tcp_chr_telnet_init (Chardev *chr);static void tcp_chr_reconn_timer_cancel (SocketChardev *s) {
@@ -567,6 +569,15 @@ static void tcp_chr_connect(void *opaque)qemu_chr_be_event (chr,CHR_EVENT_OPENED ); } +static void tcp_chr_telnet_destroy (SocketChardev *s) +{ +if (s->telnet_source) { +g_source_destroy (s->telnet_source); +g_source_unref (s->telnet_source); + s->telnet_source =NULL ; + } +} +static void tcp_chr_update_read_handler (Chardev *chr) {SocketChardev *s =SOCKET_CHARDEV (chr);
@@ -580,6 +591,11 @@ static void tcp_chr_update_read_handler(Chardev *chr)tcp_chr_net_listener_setup (s, true); } +if (s->telnet_source) { +tcp_chr_telnet_destroy (s); +tcp_chr_telnet_init (CHARDEV (s)); + } +if (!s->connected) {return ; }
@@ -604,6 +620,7 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, gpointer user_data) {TCPChardevTelnetInit *init = user_data; +SocketChardev *s =SOCKET_CHARDEV (init->chr);ssize_t ret; ret =qio_channel_write (ioc, init->buf, init->buflen,NULL );
@@ -628,6 +645,8 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, end:g_free (init); +g_source_unref (s->telnet_source); + s->telnet_source =NULL ;return G_SOURCE_REMOVE ; }
@@ -667,10 +686,10 @@ static void tcp_chr_telnet_init(Chardev *chr)#undef IACSET -qio_channel_add_watch ( - s->ioc,G_IO_OUT , - tcp_chr_telnet_init_io, - init,NULL ); + s->telnet_source =qio_channel_add_watch_source (s->ioc,G_IO_OUT , + tcp_chr_telnet_init_io, + init,NULL , + chr->gcontext); }
@@ -843,6 +862,7 @@ static void char_socket_finalize(Object *obj)tcp_chr_free_connection (chr);tcp_chr_reconn_timer_cancel (s);qapi_free_SocketAddress (s->addr); +tcp_chr_telnet_destroy (s);if (s->listener) {tcp_chr_net_listener_setup (s, false);object_unref (OBJECT (s->listener));
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 08/15] chardev: allow telnet gsource to switch gcontext
Quoted 7 lines · Peter Xu
It was originally created by
qio_channel_add_watch()so it's always assigning the task to main context. Now we use the new API calledqio_channel_add_watch_source()so that we get the GSource handle rather than the tag ID.Meanwhile, caching the gsource in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers.
I don't see why we would ever want to dynamically switch the GMainContext in use while in middle of reading the telnet greeting.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 08/15] chardev: allow telnet gsource to switch gcontext
Quoted 10 lines · Daniel P. Berrangé
Quoted 7 lines · Peter Xu
It was originally created by
qio_channel_add_watch()so it's always assigning the task to main context. Now we use the new API calledqio_channel_add_watch_source()so that we get the GSource handle rather than the tag ID.Meanwhile, caching the gsource in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers.
I don't see why we would ever want to dynamically switch the GMainContext in use while in middle of reading the telnet greeting.
Maybe because the remote client hangs in the middle of the telnet greeting? The user of the Chardev can't know that the initial handshake hasn't been done yet.
Paolo
Re: [Qemu-devel] [PATCH v2 08/15] chardev: allow telnet gsource to switch gcontext
Quoted 7 lines · Paolo Bonzini
Quoted 6 lines · Daniel P. Berrangé
Quoted 5 lines · Peter Xu
It was originally created by
qio_channel_add_watch()so it's always assigning the task to main context. Now we use the new API calledqio_channel_add_watch_source()so that we get the GSource handle rather than the tag ID.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Meanwhile, caching the gsource in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers.
I don't see why we would ever want to dynamically switch the GMainContext in use while in middle of reading the telnet greeting.
Maybe because the remote client hangs in the middle of the telnet greeting? The user of the Chardev can't know that the initial handshake hasn't been done yet.
Ah, this reminded me that I should better cache the TCPChardevTelnetInit struct, otherwise when context changes we'll possibly restart a telnet handshake.
Actually if only considering the monitor-OOB series (which is the only one now who may change the context) it's not really necessary, since the context will only be changed once when init monitors. But it's easy to even achieve a higher goal to support real dynamic switch for telnet connections. So I think I'll try that in my next post.
Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 08/15] chardev: allow telnet gsource to switch gcontext
In reply to Paolo BonziniQuoted 7 lines · Paolo Bonzini
Quoted 6 lines · Daniel P. Berrangé
Quoted 5 lines · Peter Xu
It was originally created by
qio_channel_add_watch()so it's always assigning the task to main context. Now we use the new API calledqio_channel_add_watch_source()so that we get the GSource handle rather than the tag ID.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Meanwhile, caching the gsource in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers.
I don't see why we would ever want to dynamically switch the GMainContext in use while in middle of reading the telnet greeting.
Maybe because the remote client hangs in the middle of the telnet greeting? The user of the Chardev can't know that the initial handshake hasn't been done yet.
NB, the chardev will emit the CHR_EVENT_OPENED event once the connection is successfully established, which includes completion of the telnet and/or TLS handshake.
I'm just not seeing what code in QEMU would actually trigger a decision to change the GMainContext, in between the accept() of the socket, and the CHR_EVENT_OPENED, since we don't tell anyone that the accept() has actually taken place - they first they'll know of a new client being connected is when the CHR_EVENT_OPENED is emitted.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
PATCH v2 9/15 qio: non-default context for threaded qtask
In reply to Peter Xuqio_task_run_in_thread() allows main thread to run blocking operations in the background. However it has an assumption on that it's always working with the default context. This patch tries to allow the threaded QIO task framework to run with non-default gcontext.
Currently no functional change so far, so the QIOTasks are still always running on main context.
--- include/io/task.h | 6 ++++-- io/channel-socket.c | 9 ++++++--- io/dns-resolver.c | 3 ++- io/task.c | 20 ++++++++++++++++++-- tests/test-io-task.c | 2 ++ 5 files changed, 32 insertions(+), 8 deletions(-)
include/io/task.h +4 -2
@@ -227,15 +227,17 @@ QIOTask *qio_task_new(Object *source,* @worker: the function to invoke in a thread * @opaque: opaque data to pass to @worker * @destroy: function to free @opaque +* @context: the context to run the complete hook * * Run a task in a background thread. When @worker * returns it will call qio_task_complete() in -* the main event thread context. +* the event thread context that provided. */ void qio_task_run_in_thread (QIOTask *task,QIOTaskWorker worker,gpointer opaque, -GDestroyNotify destroy); +GDestroyNotify destroy, +GMainContext *context);/** * qio_task_complete:
io/channel-socket.c +6 -3
@@ -187,7 +187,8 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,qio_task_run_in_thread (task, qio_channel_socket_connect_worker, addrCopy, - (GDestroyNotify )qapi_free_SocketAddress); + (GDestroyNotify )qapi_free_SocketAddress, +NULL ); }
@@ -245,7 +246,8 @@ void qio_channel_socket_listen_async(QIOChannelSocket *ioc,qio_task_run_in_thread (task, qio_channel_socket_listen_worker, addrCopy, - (GDestroyNotify )qapi_free_SocketAddress); + (GDestroyNotify )qapi_free_SocketAddress, +NULL ); }
@@ -321,7 +323,8 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc,qio_task_run_in_thread (task, qio_channel_socket_dgram_worker, data, - qio_channel_socket_dgram_worker_free); + qio_channel_socket_dgram_worker_free, +NULL ); }
io/dns-resolver.c +2 -1
@@ -233,7 +233,8 @@ void qio_dns_resolver_lookup_async(QIODNSResolver *resolver,qio_task_run_in_thread (task, qio_dns_resolver_lookup_worker, data, - qio_dns_resolver_lookup_data_free); + qio_dns_resolver_lookup_data_free, +NULL ); }
io/task.c +18 -2
@@ -77,6 +77,7 @@ struct QIOTaskThreadData {QIOTaskWorker worker;gpointer opaque;GDestroyNotify destroy; +GMainContext *context; };
@@ -91,6 +92,10 @@ static gboolean qio_task_thread_result(gpointer opaque) data->destroy (data->opaque); } +if (data->context) { +g_main_context_unref (data->context); + } +g_free (data);return FALSE;
@@ -100,6 +105,7 @@ static gboolean qio_task_thread_result(gpointer opaque)static gpointer qio_task_thread_worker (gpointer opaque) {struct QIOTaskThreadData *data = opaque; +GSource *idle;trace_qio_task_thread_run (data->task); data->worker (data->task, data->opaque);
@@ -110,7 +116,11 @@ static gpointer qio_task_thread_worker(gpointer opaque)* the worker results */ trace_qio_task_thread_exit (data->task); -g_idle_add (qio_task_thread_result, data); + + idle =g_idle_source_new (); +g_source_set_callback (idle, qio_task_thread_result, data,NULL ); +g_source_attach (idle, data->context); +return NULL ; }
@@ -118,15 +128,21 @@ static gpointer qio_task_thread_worker(gpointer opaque)void qio_task_run_in_thread (QIOTask *task,QIOTaskWorker worker,gpointer opaque, -GDestroyNotify destroy) +GDestroyNotify destroy, +GMainContext *context) { struct QIOTaskThreadData *data = g_new0(struct QIOTaskThreadData, 1);QemuThread thread; +if (context) { +g_main_context_ref (context); + } + data->task = task; data->worker = worker; data->opaque = opaque; data->destroy = destroy; + data->context = context;trace_qio_task_thread_start (task, worker, opaque); qemu_thread_create(&thread,
tests/test-io-task.c +2 -0
@@ -187,6 +187,7 @@ static void test_task_thread_complete(void)qio_task_run_in_thread (task, test_task_thread_worker, &data, +NULL ,NULL );g_main_loop_run (data.loop);
@@ -228,6 +229,7 @@ static void test_task_thread_failure(void)qio_task_run_in_thread (task, test_task_thread_worker, &data, +NULL ,NULL );g_main_loop_run (data.loop);
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 09/15] qio: non-default context for threaded qtask
Quoted 8 lines · Peter Xu
qio_task_run_in_thread()allows main thread to run blocking operations in the background. However it has an assumption on that it's always working with the default context. This patch tries to allow the threaded QIO task framework to run with non-default gcontext.Currently no functional change so far, so the QIOTasks are still always running on main context.
Quoted 9 lines
Signed-off-by Peter Xu <[email protected]>--- include/io/task.h | 6 ++++-- io/channel-socket.c | 9 ++++++--- io/dns-resolver.c | 3 ++- io/task.c | 20 ++++++++++++++++++-- tests/test-io-task.c | 2 ++ 5 files changed, 32 insertions(+), 8 deletions(-)
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 09/15] qio: non-default context for threaded qtask
In reply to Peter XuQuoted 1 line · Peter Xu
+ * @context: the context to run the complete hook
Please note the behavior for NULL context here, too.
Paolo
Quoted 11 lines
* Run a task in a background thread. When @worker
* returns it will callqio_task_complete()in
- * the main event thread context.
+ * the event thread context that provided. */
void qio_task_run_in_thread(QIOTask *task,
QIOTaskWorker worker, gpointer opaque,include/io/task.h +2
-1- GDestroyNotify destroy); +GDestroyNotify destroy, + GMainContext *context);
PATCH v2 10/15 qio: non-default context for async conn
In reply to Peter XuWe have worked on qio_task_run_in_thread() already. Further, let qio_channel_socket_connect_async() pass that context to it.
--- chardev/char-socket.c | 4 ++-- include/io/channel-socket.h | 4 +++- io/channel-socket.c | 5 +++-- migration/socket.c | 3 ++- tests/test-io-channel-socket.c | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)
chardev/char-socket.c +2 -2
@@ -911,7 +911,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque)tcp_chr_set_client_ioc_name (chr, sioc);qio_channel_socket_connect_async (sioc, s->addr, qemu_chr_socket_connected, - chr,NULL ); + chr,NULL ,NULL );return false; }
@@ -995,7 +995,7 @@ static void qmp_chardev_open_socket(Chardev *chr,tcp_chr_set_client_ioc_name (chr, sioc);qio_channel_socket_connect_async (sioc, s->addr, qemu_chr_socket_connected, - chr,NULL ); + chr,NULL ,NULL ); }else {if (s->is_listen) {char *name;
include/io/channel-socket.h +3 -1
@@ -101,6 +101,7 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,* @callback: the function to invoke on completion * @opaque: user data to pass to @callback * @destroy: the function to free @opaque +* @context: the context to run the async task * * Attempt to connect to the address @addr. This method * will run in the background so the caller will regain
@@ -113,7 +114,8 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,SocketAddress *addr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context);/**
io/channel-socket.c +3 -2
@@ -173,7 +173,8 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,SocketAddress *addr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy) + GDestroyNotify destroy, + GMainContext *context) { QIOTask *task = qio_task_new(OBJECT (ioc), callback, opaque, destroy);
@@ -188,7 +189,7 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc, qio_channel_socket_connect_worker, addrCopy, (GDestroyNotify )qapi_free_SocketAddress, - NULL); + context); }
migration/socket.c +2 -1
@@ -103,7 +103,8 @@ static void socket_start_outgoing_migration(MigrationState *s, saddr, socket_outgoing_migration, data, - socket_connect_data_free); + socket_connect_data_free, + NULL);qapi_free_SocketAddress (saddr); }
tests/test-io-channel-socket.c +1 -1
@@ -200,7 +200,7 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,qio_channel_socket_connect_async (QIO_CHANNEL_SOCKET (*src), connect_addr, - test_io_channel_complete, &data,NULL ); + test_io_channel_complete, &data,NULL ,NULL );g_main_loop_run (data.loop);g_main_context_iteration (g_main_context_default (), FALSE);
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 10/15] qio: non-default context for async conn
Quoted 25 lines · Peter Xu
We have worked on
qio_task_run_in_thread()already. Further, letqio_channel_socket_connect_async()pass that context to it.Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 4 ++-- include/io/channel-socket.h | 4 +++- io/channel-socket.c | 5 +++-- migration/socket.c | 3 ++- tests/test-io-channel-socket.c | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)include/io/channel-socket.h +1
-0@@ -101,6 +101,7 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,* @callback: the function to invoke on completion * @opaque: user data to pass to @callback * @destroy: the function to free @opaque +* @context: the context to run the async task * * Attempt to connect to the address @addr. This method * will run in the background so the caller will regain
include/io/channel-socket.h void qio_channel_socket_connect_async(QIOChannelSocket *ioc, · line 118
Quoted 6 lines
include/io/channel-socket.h +2
-1@@ -113,7 +114,8 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,SocketAddress *addr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context);
If you're going to add a GMainContext() to connect_async, then please also do it for listen_async and dgram_async at the same time, so we remain consistent in API design.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 10/15] qio: non-default context for async conn
Quoted 28 lines · Daniel P. Berrangé
Quoted 27 lines · Peter Xu
We have worked on
qio_task_run_in_thread()already. Further, letqio_channel_socket_connect_async()pass that context to it.Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 4 ++-- include/io/channel-socket.h | 4 +++- io/channel-socket.c | 5 +++-- migration/socket.c | 3 ++- tests/test-io-channel-socket.c | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)include/io/channel-socket.h +1
-0@@ -101,6 +101,7 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,* @callback: the function to invoke on completion * @opaque: user data to pass to @callback * @destroy: the function to free @opaque +* @context: the context to run the async task * * Attempt to connect to the address @addr. This method * will run in the background so the caller will regain @@ -113,7 +114,8 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,SocketAddress *addr, QIOTaskFunc callback,
Quoted 8 lines
include/io/channel-socket.h void qio_channel_socket_connect_async(QIOChannelSocket *ioc, · line 118
Quoted 4 lines
include/io/channel-socket.h +2
-1gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context);If you're going to add a
GMainContext()toconnect_async, then please also do it forlisten_asyncanddgram_asyncat the same time, so we remain consistent in API design.
Sure. Thanks,
Signature · 1 line
Peter Xu
PATCH v2 11/15 qio: non-default context for TLS handshake
In reply to Peter Xuqio_channel_tls_handshake_full() is introduced to allow the TLS to be run on a non-default context. Still, no functional change.
--- include/io/channel-tls.h | 17 ++++++++++++++++ io/channel-tls.c | 51 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 14 deletions(-)
include/io/channel-tls.h +17 -0
@@ -128,6 +128,23 @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,gpointer opaque, GDestroyNotify destroy); +/** +* qio_channel_tls_handshake_full: +* @ioc: the TLS channel object +* @func: the callback to invoke when completed +* @opaque: opaque data to pass to @func +* @destroy: optional callback to free @opaque +* @context: the context that TLS handshake will run with +* +* Similar to qio_channel_tls_handshake(), but allows the task to be +* run on a specific context. +*/ +void qio_channel_tls_handshake_full (QIOChannelTLS *ioc, +QIOTaskFunc func, +gpointer opaque, +GDestroyNotify destroy, +GMainContext *context); +/** * qio_channel_tls_get_session: * @ioc: the TLS channel object
io/channel-tls.c +37 -14
94 lines not on this page · raw message
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 11/15] qio: non-default context for TLS handshake
Quoted 18 lines · Peter Xu
qio_channel_tls_handshake_full()is introduced to allow the TLS to be run on a non-default context. Still, no functional change.Signed-off-by Peter Xu <[email protected]>--- include/io/channel-tls.h | 17 ++++++++++++++++ io/channel-tls.c | 51 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 14 deletions(-)static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
io/channel-tls.c +2
-1- QIOTask *task) + QIOTask *task, + GMainContext *context) {Error *err =NULL ;QCryptoTLSSessionHandshakeStatus status;
io/channel-tls.c static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, · line 183
Quoted 7 lines
io/channel-tls.c +4
-0@@ -171,6 +177,11 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,qio_task_complete (task); }else {GIOCondition condition; +QIOChannelTLSData *data =g_new0 (typeof (*data),1 ); + + data->task = task; + data->context = context;
The 'context' reference is only valid for as long as the caller exists. So you need to acquire a reference on 'context' here....
Quoted 6 lines
io/channel-tls.c +1
-1@@ -191,20 +203,23 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, GIOCondition condition, gpointer user_data) { -QIOTask *task = user_data; +QIOChannelTLSData *data = user_data;
io/channel-tls.c static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, · line 214
Quoted 10 lines
io/channel-tls.c +4
-2+QIOTask *task = data->task; +GMainContext *context = data->context;QIOChannelTLS *tioc =QIO_CHANNEL_TLS (qio_task_get_source (task)); -qio_channel_tls_handshake_task ( - tioc, task); +g_free (data); +qio_channel_tls_handshake_task (tioc, task, context);
And release the reference on context here.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 11/15] qio: non-default context for TLS handshake
Quoted 42 lines · Daniel P. Berrangé
Quoted 18 lines · Peter Xu
qio_channel_tls_handshake_full()is introduced to allow the TLS to be run on a non-default context. Still, no functional change.Signed-off-by Peter Xu <[email protected]>--- include/io/channel-tls.h | 17 ++++++++++++++++ io/channel-tls.c | 51 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 14 deletions(-)static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
io/channel-tls.c +2
-1- QIOTask *task) + QIOTask *task, + GMainContext *context) {Error *err =NULL ;QCryptoTLSSessionHandshakeStatus status;io/channel-tls.c static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, · line 183
Quoted 7 lines
io/channel-tls.c +4
-0@@ -171,6 +177,11 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,qio_task_complete (task); }else {GIOCondition condition; +QIOChannelTLSData *data =g_new0 (typeof (*data),1 ); + + data->task = task; + data->context = context;The 'context' reference is only valid for as long as the caller exists. So you need to acquire a reference on 'context' here....
Quoted 11 lines
io/channel-tls.c +3
-1@@ -191,20 +203,23 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, GIOCondition condition, gpointer user_data) { -QIOTask *task = user_data; +QIOChannelTLSData *data = user_data; +QIOTask *task = data->task; +GMainContext *context = data->context;QIOChannelTLS *tioc =QIO_CHANNEL_TLS (qio_task_get_source (task));
Quoted 7 lines
io/channel-tls.c static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
Quoted 5 lines
io/channel-tls.c +2
-2-qio_channel_tls_handshake_task ( - tioc, task); +g_free (data); +qio_channel_tls_handshake_task (tioc, task, context);And release the reference on context here.
Yeah, fixed both. Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 11/15] qio: non-default context for TLS handshake
In reply to Peter XuQuoted 7 lines · Peter Xu
include/io/channel-tls.h +7
-0+/** +* qio_channel_tls_handshake_full: +* @ioc: the TLS channel object +* @func: the callback to invoke when completed +* @opaque: opaque data to pass to @func +* @destroy: optional callback to free @opaque +* @context: the context that TLS handshake will run with
include/io/channel-tls.h void qio_channel_tls_handshake(QIOChannelTLS *ioc, · line 147
Quoted 10 lines
include/io/channel-tls.h +10
-0+* +* Similar to qio_channel_tls_handshake(), but allows the task to be +* run on a specific context. +*/ +void qio_channel_tls_handshake_full (QIOChannelTLS *ioc, +QIOTaskFunc func, +gpointer opaque, +GDestroyNotify destroy, +GMainContext *context); +
You're not consistent in introducing "_full" functions. I would add the argument directly to the qio_channel_tls_handshake() function.
Paolo
Re: [Qemu-devel] [PATCH v2 11/15] qio: non-default context for TLS handshake
Quoted 13 lines · Paolo Bonzini
Quoted 12 lines · Peter Xu
include/io/channel-tls.h +12
-0+/** +* qio_channel_tls_handshake_full: +* @ioc: the TLS channel object +* @func: the callback to invoke when completed +* @opaque: opaque data to pass to @func +* @destroy: optional callback to free @opaque +* @context: the context that TLS handshake will run with +* +* Similar to qio_channel_tls_handshake(), but allows the task to be +* run on a specific context. +*/ +void qio_channel_tls_handshake_full(QIOChannelTLS *ioc,
Quoted 8 lines
include/io/channel-tls.h void qio_channel_tls_handshake(QIOChannelTLS *ioc, · line 147
Quoted 5 lines
include/io/channel-tls.h +5
-0+QIOTaskFunc func, + gpointer opaque, + GDestroyNotify destroy, + GMainContext *context); +You're not consistent in introducing "
_full" functions. I would add the argument directly to theqio_channel_tls_handshake()function.
Will take your advise. Thanks,
Signature · 1 line
Peter Xu
PATCH v2 12/15 chardev: introduce chr_machine_done hook
In reply to Peter XuIntroduce ChardevClass.chr_machine_done() hook so that chardevs can run customized procedures after machine init.
There was an existing mux user already that did similar thing but used a raw machine done notifier. Generalize it into a framework, and let the mux chardevs provide such a class-specific hook to achieve the same thing. Then we can move the mux related code to the char-mux.c file.
This notifier framework will be further leverged by other type of chardevs soon.
--- chardev/char-mux.c | 29 +++++++++++++++++++++++++++++ chardev/char.c | 43 +++++++++++++++++-------------------------- include/chardev/char.h | 2 ++ 3 files changed, 48 insertions(+), 26 deletions(-)
chardev/char-mux.c +29 -0
@@ -347,6 +347,34 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend, mux->chardev =g_strdup (chardev); } +/** +* Called after processing of default and command-line-specified +* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached +* to a mux chardev. This is done here to ensure that +* output/prompts/banners are only displayed for the FE that has +* focus when initial command-line processing/machine init is +* completed. +* +* After this point, any new FE attached to any new or existing +* mux will receive CHR_EVENT_OPENED notifications for the BE +* immediately. +*/ +static int open_muxes (Chardev *chr) +{ +/* Set it multiple times won't hurt */ + muxes_realized = true; + +/* send OPENED to all already-attached FEs */ +mux_chr_send_all_event (chr,CHR_EVENT_OPENED ); +/* +* mark mux as OPENED so any new FEs will immediately receive +* OPENED event +*/ +qemu_chr_be_event (chr,CHR_EVENT_OPENED ); + +return 0 ; +} +static void char_mux_class_init (ObjectClass *oc,void *data) {ChardevClass *cc =CHARDEV_CLASS (oc);
@@ -357,6 +385,7 @@ static void char_mux_class_init(ObjectClass *oc, void *data) cc->chr_accept_input = mux_chr_accept_input; cc->chr_add_watch = mux_chr_add_watch; cc->chr_be_event = mux_chr_be_event; + cc->chr_machine_done = open_muxes; }static const TypeInfo char_mux_type_info = {
chardev/char.c +17 -26
64 lines not on this page · raw message
include/chardev/char.h +2 -0
@@ -247,6 +247,8 @@ typedef struct ChardevClass {void (*chr_set_echo)(Chardev *chr,bool echo);void (*chr_set_fe_open)(Chardev *chr,int fe_open);void (*chr_be_event)(Chardev *s,int event); +/* Return 0 if succeeded, 1 if failed */ +int (*chr_machine_done)(Chardev *chr); } ChardevClass; Chardev *qemu_chardev_new(const char *id, const char *typename,
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 12/15] chardev: introduce chr_machine_done hook
Quoted 11 lines · Peter Xu
Introduce
ChardevClass.chr_machine_done()hook so that chardevs can run customized procedures after machine init.There was an existing mux user already that did similar thing but used a raw machine done notifier. Generalize it into a framework, and let the mux chardevs provide such a class-specific hook to achieve the same thing. Then we can move the mux related code to the
char-mux.cfile.This notifier framework will be further leverged by other type of chardevs soon.
Quoted 6 lines
Signed-off-by Peter Xu <[email protected]>--- chardev/char-mux.c | 29 +++++++++++++++++++++++++++++ chardev/char.c | 43 +++++++++++++++++-------------------------- include/chardev/char.h | 2 ++ 3 files changed, 48 insertions(+), 26 deletions(-)
Modulo the note on muxes_realized (see patch 15/15),
PATCH v2 13/15 char: use chardev's gcontext for async connect
In reply to Peter XuGeneralize the function to create the async QIO task connection. Also, fix the context pointer to use the chardev's gcontext.
--- chardev/char-socket.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-)
chardev/char-socket.c +14 -11
@@ -894,11 +894,22 @@ cleanup:object_unref (OBJECT (sioc)); } +static void tcp_chr_connect_async (Chardev *chr) +{ +SocketChardev *s =SOCKET_CHARDEV (chr); +QIOChannelSocket *sioc; + + sioc =qio_channel_socket_new (); +tcp_chr_set_client_ioc_name (chr, sioc); +qio_channel_socket_connect_async (sioc, s->addr, + qemu_chr_socket_connected, + chr,NULL , chr->gcontext); +} +static gboolean socket_reconnect_timeout (gpointer opaque) {Chardev *chr =CHARDEV (opaque);SocketChardev *s =SOCKET_CHARDEV (opaque); -QIOChannelSocket *sioc;g_source_unref (s->reconnect_timer); s->reconnect_timer =NULL ;
@@ -907,11 +918,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque)return false; } - sioc =qio_channel_socket_new (); -tcp_chr_set_client_ioc_name (chr, sioc); -qio_channel_socket_connect_async (sioc, s->addr, - qemu_chr_socket_connected, - chr,NULL ,NULL ); +tcp_chr_connect_async (chr);return false; }
@@ -991,11 +998,7 @@ static void qmp_chardev_open_socket(Chardev *chr, }if (s->reconnect_time) { - sioc =qio_channel_socket_new (); -tcp_chr_set_client_ioc_name (chr, sioc); -qio_channel_socket_connect_async (sioc, s->addr, - qemu_chr_socket_connected, - chr,NULL ,NULL ); +tcp_chr_connect_async (chr); }else {if (s->is_listen) {char *name;
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 13/15] char: use chardev's gcontext for async connect
Quoted 53 lines · Peter Xu
Generalize the function to create the async QIO task connection. Also, fix the context pointer to use the chardev's gcontext.
Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-)chardev/char-socket.c +13
-6@@ -894,11 +894,22 @@ cleanup:object_unref (OBJECT (sioc)); } +static void tcp_chr_connect_async (Chardev *chr) +{ +SocketChardev *s =SOCKET_CHARDEV (chr); +QIOChannelSocket *sioc; + + sioc =qio_channel_socket_new (); +tcp_chr_set_client_ioc_name (chr, sioc); +qio_channel_socket_connect_async (sioc, s->addr, + qemu_chr_socket_connected, + chr,NULL , chr->gcontext); +} +static gboolean socket_reconnect_timeout (gpointer opaque) {Chardev *chr =CHARDEV (opaque);SocketChardev *s =SOCKET_CHARDEV (opaque); -QIOChannelSocket *sioc;g_source_unref (s->reconnect_timer); s->reconnect_timer =NULL ;@@ -907,11 +918,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque)return false; } - sioc =qio_channel_socket_new (); -tcp_chr_set_client_ioc_name (chr, sioc); -qio_channel_socket_connect_async (sioc, s->addr, - qemu_chr_socket_connected, - chr,NULL ,NULL ); +tcp_chr_connect_async (chr);return false; }@@ -991,11 +998,7 @@ static void qmp_chardev_open_socket(Chardev *chr, }
chardev/char-socket.c static void qmp_chardev_open_socket(Chardev *chr, · line 1004
Quoted 10 lines
chardev/char-socket.c +1
-5if (s->reconnect_time) { - sioc =qio_channel_socket_new (); -tcp_chr_set_client_ioc_name (chr, sioc); -qio_channel_socket_connect_async (sioc, s->addr, - qemu_chr_socket_connected, - chr,NULL ,NULL ); +tcp_chr_connect_async (chr); }else {if (s->is_listen) {char *name;
PATCH v2 14/15 chardev: tcp: postpone async connection setup
In reply to Peter XuThis patch allows the socket chardev async connection be setup with non-default gcontext. We do it by postponing the setup to machine done, since until then we can know which context we should run the async operation on.
--- chardev/char-socket.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
chardev/char-socket.c +14 -3
@@ -997,9 +997,8 @@ static void qmp_chardev_open_socket(Chardev *chr, s->reconnect_time = reconnect; } -if (s->reconnect_time) { -tcp_chr_connect_async (chr); - }else { +/* If reconnect_time is set, will do that in chr_machine_done. */ +if (!s->reconnect_time) {if (s->is_listen) {char *name; s->listener =qio_net_listener_new ();
@@ -1128,6 +1127,17 @@ char_socket_get_connected(Object *obj, Error **errp)return s->connected; } +static int tcp_chr_machine_done_hook (Chardev *chr) +{ +SocketChardev *s =SOCKET_CHARDEV (chr); + +if (s->reconnect_time) { +tcp_chr_connect_async (chr); + } + +return 0 ; +} +static void char_socket_class_init (ObjectClass *oc,void *data) {ChardevClass *cc =CHARDEV_CLASS (oc);
@@ -1143,6 +1153,7 @@ static void char_socket_class_init(ObjectClass *oc, void *data) cc->chr_add_client = tcp_chr_add_client; cc->chr_add_watch = tcp_chr_add_watch; cc->chr_update_read_handler = tcp_chr_update_read_handler; + cc->chr_machine_done = tcp_chr_machine_done_hook; object_class_property_add(oc, "addr", "SocketAddress", char_socket_get_addr, NULL,
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 14/15] chardev: tcp: postpone async connection setup
Quoted 9 lines · Peter Xu
This patch allows the socket chardev async connection be setup with non-default gcontext. We do it by postponing the setup to machine done, since until then we can know which context we should run the async operation on.
Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
I don't like this as it is special casing behaviour wrt GMainContext only the the case where the chardev is configured as a client with non-blocking connect. So any code that uses chardevs and wants to set a different GMainContext may or may not work, depending on whether the user gave the ',wait' option to the chardev. I'm struggling to see why this is really needed at all.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 14/15] chardev: tcp: postpone async connection setup
Quoted 11 lines · Daniel P. Berrangé
Quoted 9 lines · Peter Xu
This patch allows the socket chardev async connection be setup with non-default gcontext. We do it by postponing the setup to machine done, since until then we can know which context we should run the async operation on.
Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
Quoted 6 lines
I don't like this as it is special casing behaviour wrt GMainContext only the the case where the chardev is configured as a client with non-blocking connect. So any code that uses chardevs and wants to set a different GMainContext may or may not work, depending on whether the user gave the ',wait' option to the chardev. I'm struggling to see why this is really needed at all.
Not sure whether I fully got your point, but IMHO when "wait" is there we should be perfectly fine too if with all the TLS/TELNET patches in the this series. And for sure this patch only solves the problem when "wait" is specified.
Or say, with this series, all configuration of chardev _should_ work with non-default context now. If not, then I must have missed something else (which may be possible), then I would be very glad that anyone can give me a hint on where. Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 14/15] chardev: tcp: postpone async connection setup
In reply to Peter XuQuoted 46 lines · Peter Xu
This patch allows the socket chardev async connection be setup with non-default gcontext. We do it by postponing the setup to machine done, since until then we can know which context we should run the async operation on.
Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)chardev/char-socket.c +13
-3@@ -997,9 +997,8 @@ static void qmp_chardev_open_socket(Chardev *chr, s->reconnect_time = reconnect; } -if (s->reconnect_time) { -tcp_chr_connect_async (chr); - }else { +/* If reconnect_time is set, will do that in chr_machine_done. */ +if (!s->reconnect_time) {if (s->is_listen) {char *name; s->listener =qio_net_listener_new ();@@ -1128,6 +1127,17 @@ char_socket_get_connected(Object *obj, Error **errp)return s->connected; } +static int tcp_chr_machine_done_hook (Chardev *chr) +{ +SocketChardev *s =SOCKET_CHARDEV (chr); + +if (s->reconnect_time) { +tcp_chr_connect_async (chr); + } + +return 0 ; +} +static void char_socket_class_init (ObjectClass *oc,void *data) {ChardevClass *cc =CHARDEV_CLASS (oc);
chardev/char-socket.c static void char_socket_class_init(ObjectClass *oc, void *data) · line 1159
Quoted 7 lines
chardev/char-socket.c +1
-0@@ -1143,6 +1153,7 @@ static void char_socket_class_init(ObjectClass *oc, void *data) cc->chr_add_client = tcp_chr_add_client; cc->chr_add_watch = tcp_chr_add_watch; cc->chr_update_read_handler = tcp_chr_update_read_handler; + cc->chr_machine_done = tcp_chr_machine_done_hook; object_class_property_add(oc, "addr", "SocketAddress", char_socket_get_addr, NULL,
PATCH v2 15/15 chardev: tcp: postpone TLS work until machine done
In reply to Peter XuTLS handshake may create background GSource tasks, while we won't know the correct GMainContext until the whole chardev (including frontend) inited. Let's postpone the initial TLS handshake until machine done.
If we dynamically add tcp chardev, it won't be affected since we have a new tcp_chr_machine_done flag to know whether we should postpone it or not.
--- chardev/char-socket.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
chardev/char-socket.c +14 -0
@@ -72,6 +72,8 @@ typedef struct {static gboolean socket_reconnect_timeout (gpointer opaque);static void tcp_chr_telnet_init (Chardev *chr); +static bool tcp_chr_machine_done; +static void tcp_chr_reconn_timer_cancel (SocketChardev *s) {if (s->reconnect_timer) {
@@ -719,6 +721,11 @@ static void tcp_chr_tls_init(Chardev *chr)Error *err =NULL ;gchar *name; +if (!tcp_chr_machine_done) { +/* This will be postponed to machine_done notifier */ +return ; + } +if (s->is_listen) { tioc = qio_channel_tls_new_server( s->ioc, s->tls_creds,
@@ -1131,10 +1138,17 @@ static int tcp_chr_machine_done_hook(Chardev *chr) {SocketChardev *s =SOCKET_CHARDEV (chr); +/* Set it multiple times won't hurt */ + tcp_chr_machine_done = true; +if (s->reconnect_time) {tcp_chr_connect_async (chr); } +if (s->tls_creds) { +tcp_chr_tls_init (chr); + } +return 0 ; }
Signature · 1 line
2.14.3
Re: [Qemu-devel] [PATCH v2 15/15] chardev: tcp: postpone TLS work until machine done
Quoted 4 lines · Peter Xu
TLS handshake may create background GSource tasks, while we won't know the correct GMainContext until the whole chardev (including frontend) inited. Let's postpone the initial TLS handshake until machine done.
Quoted 8 lines
If we dynamically add tcp chardev, it won't be affected since we have a new
tcp_chr_machine_doneflag to know whether we should postpone it or not.Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
I don't like this patch either for the same reasons as previous patch - its creating different behaviour depending on whether the 'wait' flag happens to have been set in -chardev.
Quoted 47 lines
chardev/char-socket.c +14
-0@@ -72,6 +72,8 @@ typedef struct {static gboolean socket_reconnect_timeout (gpointer opaque);static void tcp_chr_telnet_init (Chardev *chr); +static bool tcp_chr_machine_done; +static void tcp_chr_reconn_timer_cancel (SocketChardev *s) {if (s->reconnect_timer) {@@ -719,6 +721,11 @@ static void tcp_chr_tls_init(Chardev *chr)Error *err =NULL ;gchar *name; +if (!tcp_chr_machine_done) { +/* This will be postponed to machine_done notifier */ +return ; + } +if (s->is_listen) { tioc = qio_channel_tls_new_server( s->ioc, s->tls_creds,@@ -1131,10 +1138,17 @@ static int tcp_chr_machine_done_hook(Chardev *chr) {SocketChardev *s =SOCKET_CHARDEV (chr); +/* Set it multiple times won't hurt */ + tcp_chr_machine_done = true; +if (s->reconnect_time) {tcp_chr_connect_async (chr); } +if (s->tls_creds) { +tcp_chr_tls_init (chr); + } +return 0 ; }Signature · 1 line
2.14.3
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH v2 15/15] chardev: tcp: postpone TLS work until machine done
Quoted 9 lines · Daniel P. Berrangé
Quoted 8 lines · Peter Xu
TLS handshake may create background GSource tasks, while we won't know the correct GMainContext until the whole chardev (including frontend) inited. Let's postpone the initial TLS handshake until machine done.
If we dynamically add tcp chardev, it won't be affected since we have a new
tcp_chr_machine_doneflag to know whether we should postpone it or not.
Quoted 8 lines
Quoted 4 lines
Signed-off-by Peter Xu <[email protected]>--- chardev/char-socket.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)I don't like this patch either for the same reasons as previous patch - its creating different behaviour depending on whether the 'wait' flag happens to have been set in -chardev.
IMHO it's because the socket chardev is indeed complicated... If you see qmp_chardev_open_socket(), that's where most of the complexity lies in. And as I explained, each of the patch, or group of patches, were only trying to solve a single problem.
Though I admit this patch has brought a little bit more complexity, though in the short term I don't see a better solution. And, if you consider the existing MUX machine done hook, then it's merely using the same way to do it but even cleaned it up a bit...
Please let me know if you have any suggestion that I can do it in a better way. Thanks!
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH v2 15/15] chardev: tcp: postpone TLS work until machine done
In reply to Peter XuQuoted 6 lines · Peter Xu
chardev/char-socket.c +2
-0+static bool tcp_chr_machine_done; +static void tcp_chr_reconn_timer_cancel (SocketChardev *s) {if (s->reconnect_timer) {
chardev/char-socket.c static void tcp_chr_tls_init(Chardev *chr) · line 728
Quoted 8 lines
chardev/char-socket.c +5
-0@@ -719,6 +721,11 @@ static void tcp_chr_tls_init(Chardev *chr)Error *err =NULL ;gchar *name; +if (!tcp_chr_machine_done) { +/* This will be postponed to machine_done notifier */ +return ; + } +
Can you instead add a global machine_init_done bool to vl.c and include/sysemu/sysemu.h (and make it always true in stubs/machine-init-done.c)?
Then muxes_realized can go away too.
Thanks,
Paolo
Re: [Qemu-devel] [PATCH v2 15/15] chardev: tcp: postpone TLS work until machine done
Quoted 20 lines · Paolo Bonzini
Quoted 6 lines · Peter Xu
chardev/char-socket.c +2
-0+static bool tcp_chr_machine_done; +static void tcp_chr_reconn_timer_cancel (SocketChardev *s) {if (s->reconnect_timer) {chardev/char-socket.c static void tcp_chr_tls_init(Chardev *chr) · line 728
Quoted 8 lines
chardev/char-socket.c +5
-0@@ -719,6 +721,11 @@ static void tcp_chr_tls_init(Chardev *chr)Error *err =NULL ;gchar *name; +if (!tcp_chr_machine_done) { +/* This will be postponed to machine_done notifier */ +return ; + } +Can you instead add a global
machine_init_donebool tovl.candinclude/sysemu/sysemu.h(and make it always true instubs/machine-init-done.c)?
Quoted 1 line
Then
muxes_realizedcan go away too.
Sure! I'll add a new patch for it. Thanks,
Signature · 1 line
Peter Xu
Quoted 18 lines · Peter Xu
This is another preparation work for monitor OOB seires.
V1: http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg06972.html
V2 rewrote the bottom half of the code. The first 8 patches are mostly the same, but I rewrote the last patches to solve both TLS and reconnect use cases by introducing a
machine_donehook for chardevs in general. So if I copy the problems:- migration
- incoming side: still always running on main context, while we need to be able to run some command in OOB thread [1]
- tcp chardev (non-tcp chardevs should all support non-NULL context now)
- server listening mode: QIO net listener used [2]
- TELNET session: an isolated GSource used (tcp_chr_telnet_init) [3]
- when "reconnect=N" is used, QIO threaded task is used [4]
- TLS session: QIO tls handshake is used (tcp_chr_tls_init) [5]
Quoted 2 lines
Problem [1-3] are still fixed in the old way, but [4-5] now are fixed by using the new
machine_donenotifier.
The QIO code changes all look good to me know, aside from minor comments. I really dislike all of the chardev stuff though. I think it makes the chardev code even harder to follow & rationalize behaviour of.
If you post a v3 series contaning just the qio/ directory changes, I'd queue those patches, while we discuss chardev stuff more.
I struggle to suggest better approach, because its any missing context of how the changes are going to be used, presumably by patch series yet to be posted.
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Quoted 27 lines · Daniel P. Berrangé
Quoted 18 lines · Peter Xu
This is another preparation work for monitor OOB seires.
V1: http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg06972.html
V2 rewrote the bottom half of the code. The first 8 patches are mostly the same, but I rewrote the last patches to solve both TLS and reconnect use cases by introducing a
machine_donehook for chardevs in general. So if I copy the problems:- migration
- incoming side: still always running on main context, while we need to be able to run some command in OOB thread [1]
- tcp chardev (non-tcp chardevs should all support non-NULL context now)
- server listening mode: QIO net listener used [2]
- TELNET session: an isolated GSource used (tcp_chr_telnet_init) [3]
- when "reconnect=N" is used, QIO threaded task is used [4]
- TLS session: QIO tls handshake is used (tcp_chr_tls_init) [5]Quoted 2 lines
Problem [1-3] are still fixed in the old way, but [4-5] now are fixed by using the new
machine_donenotifier.The QIO code changes all look good to me know, aside from minor comments. I really dislike all of the chardev stuff though. I think it makes the chardev code even harder to follow & rationalize behaviour of.
Quoted 6 lines
If you post a v3 series contaning just the qio/ directory changes, I'd queue those patches, while we discuss chardev stuff more.
I struggle to suggest better approach, because its any missing context of how the changes are going to be used, presumably by patch series yet to be posted.
Yeah I think I'll split the series into two.
Thank you and Paolo for the quick review comments!
Signature · 1 line
Peter Xu