From 7c28768fef4bbd7601b26c4efca4ced9c0651356 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 5 Mar 2018 14:43:19 +0800 Subject: [PATCH 1/6] qio: rename qio_task_thread_result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is strange that it was called gio_task_thread_result. Rename it to follow the naming rule of the file. Reviewed-by: Daniel P. Berrange Signed-off-by: Peter Xu Signed-off-by: Daniel P. Berrangé --- io/task.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io/task.c b/io/task.c index 3ce556017c..1a0a1c7185 100644 --- a/io/task.c +++ b/io/task.c @@ -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; } From 315409c7115b9f6b1b027899c214f4a1f706a7c5 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 5 Mar 2018 14:43:20 +0800 Subject: [PATCH 2/6] qio: introduce qio_channel_add_watch_{full|source} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firstly, 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. Signed-off-by: Peter Xu Signed-off-by: Daniel P. Berrangé --- include/io/channel.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ io/channel.c | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/include/io/channel.h b/include/io/channel.h index 3995e243a3..e8cdadb0b0 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -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: diff --git a/io/channel.c b/io/channel.c index ec4b86de7c..8dd0684f5d 100644 --- a/io/channel.c +++ b/io/channel.c @@ -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, From 938c8b79e5249d41469151e30268cfaf88bdb588 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 5 Mar 2018 14:43:21 +0800 Subject: [PATCH 3/6] qio: store gsources for net listeners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Daniel P. Berrangé --- include/io/net-listener.h | 28 +++++++++++++++---- io/net-listener.c | 58 ++++++++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/include/io/net-listener.h b/include/io/net-listener.h index 56d6da7a76..8081ac58a2 100644 --- a/include/io/net-listener.h +++ b/include/io/net-listener.h @@ -53,7 +53,7 @@ struct QIONetListener { char *name; QIOChannelSocket **sioc; - gulong *io_tag; + GSource **io_source; size_t nsioc; bool connected; @@ -119,6 +119,26 @@ int qio_net_listener_open_sync(QIONetListener *listener, void qio_net_listener_add(QIONetListener *listener, QIOChannelSocket *sioc); +/** + * 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. If %NULL, + * the default context will be used. + * + * 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 @@ -126,10 +146,8 @@ void qio_net_listener_add(QIONetListener *listener, * @data: opaque data to pass to @func * @notify: callback to free @data * - * 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. + * 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, diff --git a/io/net-listener.c b/io/net-listener.c index de38dfae99..555e8acaa4 100644 --- a/io/net-listener.c +++ b/io/net-listener.c @@ -118,29 +118,32 @@ void qio_net_listener_add(QIONetListener *listener, listener->sioc = g_renew(QIOChannelSocket *, listener->sioc, listener->nsioc + 1); - listener->io_tag = g_renew(gulong, listener->io_tag, listener->nsioc + 1); + listener->io_source = g_renew(typeof(listener->io_source[0]), + listener->io_source, + listener->nsioc + 1); listener->sioc[listener->nsioc] = sioc; - listener->io_tag[listener->nsioc] = 0; + listener->io_source[listener->nsioc] = NULL; object_ref(OBJECT(sioc)); listener->connected = true; if (listener->io_func != NULL) { object_ref(OBJECT(listener)); - listener->io_tag[listener->nsioc] = qio_channel_add_watch( + listener->io_source[listener->nsioc] = qio_channel_add_watch_source( QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN, qio_net_listener_channel_func, - listener, (GDestroyNotify)object_unref); + listener, (GDestroyNotify)object_unref, NULL); } listener->nsioc++; } -void qio_net_listener_set_client_func(QIONetListener *listener, - QIONetListenerClientFunc func, - gpointer data, - GDestroyNotify notify) +void qio_net_listener_set_client_func_full(QIONetListener *listener, + QIONetListenerClientFunc func, + gpointer data, + GDestroyNotify notify, + GMainContext *context) { size_t i; @@ -152,23 +155,32 @@ void qio_net_listener_set_client_func(QIONetListener *listener, 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_source[i]) { + g_source_destroy(listener->io_source[i]); + g_source_unref(listener->io_source[i]); + listener->io_source[i] = NULL; } } if (listener->io_func != NULL) { for (i = 0; i < listener->nsioc; i++) { object_ref(OBJECT(listener)); - listener->io_tag[i] = qio_channel_add_watch( + listener->io_source[i] = qio_channel_add_watch_source( QIO_CHANNEL(listener->sioc[i]), G_IO_IN, qio_net_listener_channel_func, - listener, (GDestroyNotify)object_unref); + listener, (GDestroyNotify)object_unref, context); } } } +void qio_net_listener_set_client_func(QIONetListener *listener, + QIONetListenerClientFunc func, + gpointer data, + GDestroyNotify notify) +{ + qio_net_listener_set_client_func_full(listener, func, data, + notify, NULL); +} struct QIONetListenerClientWaitData { QIOChannelSocket *sioc; @@ -211,9 +223,10 @@ 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; + if (listener->io_source[i]) { + g_source_destroy(listener->io_source[i]); + g_source_unref(listener->io_source[i]); + listener->io_source[i] = NULL; } } @@ -241,10 +254,10 @@ QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) if (listener->io_func != NULL) { for (i = 0; i < listener->nsioc; i++) { object_ref(OBJECT(listener)); - listener->io_tag[i] = qio_channel_add_watch( + listener->io_source[i] = qio_channel_add_watch_source( QIO_CHANNEL(listener->sioc[i]), G_IO_IN, qio_net_listener_channel_func, - listener, (GDestroyNotify)object_unref); + listener, (GDestroyNotify)object_unref, NULL); } } @@ -260,9 +273,10 @@ void qio_net_listener_disconnect(QIONetListener *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; + if (listener->io_source[i]) { + g_source_destroy(listener->io_source[i]); + g_source_unref(listener->io_source[i]); + listener->io_source[i] = NULL; } qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL); } @@ -285,7 +299,7 @@ static void qio_net_listener_finalize(Object *obj) for (i = 0; i < listener->nsioc; i++) { object_unref(OBJECT(listener->sioc[i])); } - g_free(listener->io_tag); + g_free(listener->io_source); g_free(listener->sioc); g_free(listener->name); } From a17536c594bfed94d05667b419f747b692f5fc7f Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 5 Mar 2018 14:43:22 +0800 Subject: [PATCH 4/6] qio: non-default context for threaded qtask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reviewed-by: Daniel P. Berrange Signed-off-by: Peter Xu Signed-off-by: Daniel P. Berrangé --- include/io/task.h | 7 +++++-- io/channel-socket.c | 9 ++++++--- io/dns-resolver.c | 3 ++- io/task.c | 20 ++++++++++++++++++-- tests/test-io-task.c | 2 ++ 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/io/task.h b/include/io/task.h index 6021f51336..9e09b95b2e 100644 --- a/include/io/task.h +++ b/include/io/task.h @@ -227,15 +227,18 @@ 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. If %NULL, the + * default context will be used. * * 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: diff --git a/io/channel-socket.c b/io/channel-socket.c index 8359b6683a..b4d914b767 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -188,7 +188,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); } @@ -246,7 +247,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); } @@ -322,7 +324,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); } diff --git a/io/dns-resolver.c b/io/dns-resolver.c index 8c924071c4..187f725665 100644 --- a/io/dns-resolver.c +++ b/io/dns-resolver.c @@ -234,7 +234,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); } diff --git a/io/task.c b/io/task.c index 1a0a1c7185..2886a2c1bc 100644 --- a/io/task.c +++ b/io/task.c @@ -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, diff --git a/tests/test-io-task.c b/tests/test-io-task.c index 141aa2c55d..bac1bb4e7a 100644 --- a/tests/test-io-task.c +++ b/tests/test-io-task.c @@ -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); From 8005fdd8fa1c754492776f6da14893932faa057a Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 5 Mar 2018 14:43:23 +0800 Subject: [PATCH 5/6] qio: non-default context for async conn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have worked on qio_task_run_in_thread() already. Further, let all the qio channel APIs use that context. Signed-off-by: Peter Xu Signed-off-by: Daniel P. Berrangé --- chardev/char-socket.c | 4 ++-- include/io/channel-socket.h | 15 ++++++++++++--- io/channel-socket.c | 15 +++++++++------ migration/socket.c | 3 ++- tests/test-io-channel-socket.c | 4 ++-- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 22f65971a1..b0d11387f3 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -867,7 +867,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; } @@ -951,7 +951,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; diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h index 53801f6042..d7134d2cd6 100644 --- a/include/io/channel-socket.h +++ b/include/io/channel-socket.h @@ -101,6 +101,8 @@ 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. If %NULL, the default + * context will be used. * * Attempt to connect to the address @addr. This method * will run in the background so the caller will regain @@ -113,7 +115,8 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc, SocketAddress *addr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context); /** @@ -138,6 +141,8 @@ int qio_channel_socket_listen_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. If %NULL, the default + * context will be used. * * Attempt to listen to the address @addr. This method * will run in the background so the caller will regain @@ -150,7 +155,8 @@ void qio_channel_socket_listen_async(QIOChannelSocket *ioc, SocketAddress *addr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context); /** @@ -179,6 +185,8 @@ int qio_channel_socket_dgram_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. If %NULL, the default + * context will be used. * * Attempt to initialize a datagram socket bound to * @localAddr and communicating with peer @remoteAddr. @@ -194,7 +202,8 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc, SocketAddress *remoteAddr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context); /** diff --git a/io/channel-socket.c b/io/channel-socket.c index b4d914b767..57cfb4d3a6 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -174,7 +174,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); @@ -189,7 +190,7 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc, qio_channel_socket_connect_worker, addrCopy, (GDestroyNotify)qapi_free_SocketAddress, - NULL); + context); } @@ -234,7 +235,8 @@ void qio_channel_socket_listen_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); @@ -248,7 +250,7 @@ void qio_channel_socket_listen_async(QIOChannelSocket *ioc, qio_channel_socket_listen_worker, addrCopy, (GDestroyNotify)qapi_free_SocketAddress, - NULL); + context); } @@ -310,7 +312,8 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc, SocketAddress *remoteAddr, QIOTaskFunc callback, gpointer opaque, - GDestroyNotify destroy) + GDestroyNotify destroy, + GMainContext *context) { QIOTask *task = qio_task_new( OBJECT(ioc), callback, opaque, destroy); @@ -325,7 +328,7 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc, qio_channel_socket_dgram_worker, data, qio_channel_socket_dgram_worker_free, - NULL); + context); } diff --git a/migration/socket.c b/migration/socket.c index e090097077..8a93fb1af5 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -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); } diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index d357cd2a8e..b273fd3ba2 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -179,7 +179,7 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr, lioc = qio_channel_socket_new(); qio_channel_socket_listen_async( lioc, listen_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); @@ -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); From 1939ccdaa61ce6a1f57d83277b3d41d3a9ad3c58 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 5 Mar 2018 14:43:24 +0800 Subject: [PATCH 6/6] qio: non-default context for TLS handshake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new parameter "context" is added to qio_channel_tls_handshake() is to allow the TLS to be run on a non-default context. Still, no functional change. Signed-off-by: Peter Xu Signed-off-by: Daniel P. Berrangé --- chardev/char-socket.c | 1 + include/io/channel-tls.h | 5 ++++- io/channel-tls.c | 45 ++++++++++++++++++++++++++++--------- migration/tls.c | 2 ++ nbd/client.c | 1 + nbd/server.c | 1 + tests/test-io-channel-tls.c | 2 ++ ui/vnc-auth-vencrypt.c | 1 + ui/vnc-ws.c | 1 + 9 files changed, 47 insertions(+), 12 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index b0d11387f3..58e11c6f4c 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -703,6 +703,7 @@ static void tcp_chr_tls_init(Chardev *chr) qio_channel_tls_handshake(tioc, tcp_chr_tls_handshake, chr, + NULL, NULL); } diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h index d157eb10e8..87fcaf9146 100644 --- a/include/io/channel-tls.h +++ b/include/io/channel-tls.h @@ -116,6 +116,8 @@ qio_channel_tls_new_client(QIOChannel *master, * @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. If %NULL, + * the default context will be used * * Perform the TLS session handshake. This method * will return immediately and the handshake will @@ -126,7 +128,8 @@ qio_channel_tls_new_client(QIOChannel *master, void qio_channel_tls_handshake(QIOChannelTLS *ioc, QIOTaskFunc func, gpointer opaque, - GDestroyNotify destroy); + GDestroyNotify destroy, + GMainContext *context); /** * qio_channel_tls_get_session: diff --git a/io/channel-tls.c b/io/channel-tls.c index 6182702dab..9628e6fa47 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -140,13 +140,19 @@ qio_channel_tls_new_client(QIOChannel *master, return NULL; } +struct QIOChannelTLSData { + QIOTask *task; + GMainContext *context; +}; +typedef struct QIOChannelTLSData QIOChannelTLSData; static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, GIOCondition condition, gpointer user_data); static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, - QIOTask *task) + QIOTask *task, + GMainContext *context) { Error *err = NULL; QCryptoTLSSessionHandshakeStatus status; @@ -171,6 +177,15 @@ 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; + + if (context) { + g_main_context_ref(context); + } + if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) { condition = G_IO_OUT; } else { @@ -178,11 +193,12 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, } trace_qio_channel_tls_handshake_pending(ioc, status); - qio_channel_add_watch(ioc->master, - condition, - qio_channel_tls_handshake_io, - task, - NULL); + qio_channel_add_watch_full(ioc->master, + condition, + qio_channel_tls_handshake_io, + data, + NULL, + context); } } @@ -191,12 +207,18 @@ 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)); - qio_channel_tls_handshake_task( - tioc, task); + g_free(data); + qio_channel_tls_handshake_task(tioc, task, context); + + if (context) { + g_main_context_unref(context); + } return FALSE; } @@ -204,7 +226,8 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, void qio_channel_tls_handshake(QIOChannelTLS *ioc, QIOTaskFunc func, gpointer opaque, - GDestroyNotify destroy) + GDestroyNotify destroy, + GMainContext *context) { QIOTask *task; @@ -212,7 +235,7 @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc, func, opaque, destroy); trace_qio_channel_tls_handshake_start(ioc); - qio_channel_tls_handshake_task(ioc, task); + qio_channel_tls_handshake_task(ioc, task, context); } diff --git a/migration/tls.c b/migration/tls.c index a29b35b33c..3b9e8c9263 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -105,6 +105,7 @@ void migration_tls_channel_process_incoming(MigrationState *s, qio_channel_tls_handshake(tioc, migration_tls_incoming_handshake, NULL, + NULL, NULL); } @@ -159,5 +160,6 @@ void migration_tls_channel_connect(MigrationState *s, qio_channel_tls_handshake(tioc, migration_tls_outgoing_handshake, s, + NULL, NULL); } diff --git a/nbd/client.c b/nbd/client.c index 9c3fe4aaa6..dcad23a053 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -579,6 +579,7 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, qio_channel_tls_handshake(tioc, nbd_tls_handshake, &data, + NULL, NULL); if (!data.complete) { diff --git a/nbd/server.c b/nbd/server.c index 4990a5826e..e714bfe6a1 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -599,6 +599,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, qio_channel_tls_handshake(tioc, nbd_tls_handshake, &data, + NULL, NULL); if (!data.complete) { diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c index a210d01ba5..32743b2c96 100644 --- a/tests/test-io-channel-tls.c +++ b/tests/test-io-channel-tls.c @@ -203,10 +203,12 @@ static void test_io_channel_tls(const void *opaque) qio_channel_tls_handshake(clientChanTLS, test_tls_handshake_done, &clientHandshake, + NULL, NULL); qio_channel_tls_handshake(serverChanTLS, test_tls_handshake_done, &serverHandshake, + NULL, NULL); /* diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index 7833631275..d99ea362c1 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -128,6 +128,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len qio_channel_tls_handshake(tls, vnc_tls_handshake_done, vs, + NULL, NULL); } return 0; diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index 6ccad22cef..950f1cd2ac 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -81,6 +81,7 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, qio_channel_tls_handshake(tls, vncws_tls_handshake_done, vs, + NULL, NULL); return TRUE;