From nobody Wed Oct 22 13:02:51 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1519794988712935.7964837282634; Tue, 27 Feb 2018 21:16:28 -0800 (PST) Received: from localhost ([::1]:42281 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1equ6N-0007D9-Gj for importer@patchew.org; Wed, 28 Feb 2018 00:16:27 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33722) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eqtxn-0008Pw-8N for qemu-devel@nongnu.org; Wed, 28 Feb 2018 00:07:36 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eqtxl-0000sk-Sv for qemu-devel@nongnu.org; Wed, 28 Feb 2018 00:07:35 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:47022 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eqtxl-0000sa-Ks for qemu-devel@nongnu.org; Wed, 28 Feb 2018 00:07:33 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 51B8A87ABA for ; Wed, 28 Feb 2018 05:07:33 +0000 (UTC) Received: from xz-mi.redhat.com (ovpn-12-95.pek2.redhat.com [10.72.12.95]) by smtp.corp.redhat.com (Postfix) with ESMTP id 13C952026E04; Wed, 28 Feb 2018 05:07:29 +0000 (UTC) From: Peter Xu To: qemu-devel@nongnu.org Date: Wed, 28 Feb 2018 13:06:32 +0800 Message-Id: <20180228050633.7410-14-peterx@redhat.com> In-Reply-To: <20180228050633.7410-1-peterx@redhat.com> References: <20180228050633.7410-1-peterx@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Wed, 28 Feb 2018 05:07:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Wed, 28 Feb 2018 05:07:33 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'peterx@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH 13/14] qio: allow threaded qiotask to switch contexts X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Juan Quintela , Markus Armbruster , peterx@redhat.com, "Dr . David Alan Gilbert" , Stefan Hajnoczi , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This is the part of work to allow the QIOTask to use a different gcontext rather than the default main gcontext, by providing qio_task_context_set() API. We have done some work before on doing similar things to add non-default gcontext support. The general idea is that we delete the old GSource from the main context, then re-add a new one to the new context when context changed to a non-default one. However this trick won't work easily for threaded QIOTasks since we can't easily stop a real thread and re-setup the whole thing from the very beginning. But luckily, we don't need to do anything to the thread. We just need to keep an eye on the GSource that completes the QIOTask, which is assigned to gcontext after the sync operation finished. So when we setup a non-default GMainContext for a threaded QIO task, we may face two cases: - the thread is still running the sync task: then we don't need to do anything, only to update QIOTask.context to the new context - the thread has finished the sync task and queued an idle task to main thread: then we destroy that old idle task, and re-create it on the new GMainContext. Note that along the way when we modify either idle GSource or the context, we need to take the mutex before hand, since the thread may be modifying them at the same time. Finally, call qio_task_context_set() in the tcp chardev update read handler hook if QIOTask is running. Signed-off-by: Peter Xu --- chardev/char-socket.c | 4 +++ include/io/task.h | 1 + io/task.c | 70 ++++++++++++++++++++++++++++++++++++++++++-----= ---- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 9d51b8da07..164a64ff34 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -585,6 +585,10 @@ static void tcp_chr_update_read_handler(Chardev *chr) tcp_chr_telnet_init(CHARDEV(s)); } =20 + if (s->thread_task) { + qio_task_context_set(s->thread_task, chr->gcontext); + } + if (!s->connected) { return; } diff --git a/include/io/task.h b/include/io/task.h index c6acd6489c..87e0152d8a 100644 --- a/include/io/task.h +++ b/include/io/task.h @@ -324,5 +324,6 @@ Object *qio_task_get_source(QIOTask *task); =20 void qio_task_ref(QIOTask *task); void qio_task_unref(QIOTask *task); +void qio_task_context_set(QIOTask *task, GMainContext *context); =20 #endif /* QIO_TASK_H */ diff --git a/io/task.c b/io/task.c index 080f9560ea..59bc439bdf 100644 --- a/io/task.c +++ b/io/task.c @@ -42,6 +42,9 @@ struct QIOTask { uint32_t refcount; =20 /* Threaded QIO task specific fields */ + bool has_thread; + QemuThread thread; + QemuMutex mutex; /* Protects threaded QIO task fields */ GSource *idle_source; /* The idle task to run complete routine */ GMainContext *context; /* The context that idle task will run with */ QIOTaskThreadData thread_data; @@ -57,6 +60,8 @@ QIOTask *qio_task_new(Object *source, =20 task =3D g_new0(QIOTask, 1); =20 + qemu_mutex_init(&task->mutex); + task->source =3D source; object_ref(source); task->func =3D func; @@ -88,7 +93,16 @@ static void qio_task_free(QIOTask *task) if (task->context) { g_main_context_unref(task->context); } + /* + * Make sure the thread quitted before we destroy the mutex, + * otherwise the thread might still be using it. + */ + if (task->has_thread) { + qemu_thread_join(&task->thread); + } + object_unref(task->source); + qemu_mutex_destroy(&task->mutex); =20 g_free(task); } @@ -117,12 +131,28 @@ static gboolean qio_task_thread_result(gpointer opaqu= e) return FALSE; } =20 +/* Must be with QIOTask.mutex held. */ +static void qio_task_thread_create_complete_job(QIOTask *task) +{ + GSource *idle; + + /* Remove the old if there is */ + if (task->idle_source) { + g_source_destroy(task->idle_source); + g_source_unref(task->idle_source); + } + + idle =3D g_idle_source_new(); + g_source_set_callback(idle, qio_task_thread_result, task, NULL); + g_source_attach(idle, task->context); + + task->idle_source =3D idle; +} =20 static gpointer qio_task_thread_worker(gpointer opaque) { QIOTask *task =3D opaque; QIOTaskThreadData *data =3D &task->thread_data; - GSource *idle; =20 trace_qio_task_thread_run(task); data->worker(task, data->opaque); @@ -134,10 +164,9 @@ static gpointer qio_task_thread_worker(gpointer opaque) */ trace_qio_task_thread_exit(task); =20 - idle =3D g_idle_source_new(); - g_source_set_callback(idle, qio_task_thread_result, data, NULL); - g_source_attach(idle, task->context); - task->idle_source =3D idle; + qemu_mutex_lock(&task->mutex); + qio_task_thread_create_complete_job(task); + qemu_mutex_unlock(&task->mutex); =20 return NULL; } @@ -149,24 +178,21 @@ void qio_task_run_in_thread(QIOTask *task, GDestroyNotify destroy, GMainContext *context) { - QemuThread thread; QIOTaskThreadData *data =3D &task->thread_data; =20 - if (context) { - g_main_context_ref(context); - task->context =3D context; - } + qio_task_context_set(task, context); =20 data->worker =3D worker; data->opaque =3D opaque; data->destroy =3D destroy; =20 trace_qio_task_thread_start(task, worker, opaque); - qemu_thread_create(&thread, + qemu_thread_create(&task->thread, "io-task-worker", qio_task_thread_worker, task, - QEMU_THREAD_DETACHED); + QEMU_THREAD_JOINABLE); + task->has_thread =3D true; } =20 =20 @@ -235,3 +261,23 @@ void qio_task_unref(QIOTask *task) qio_task_free(task); } } + +void qio_task_context_set(QIOTask *task, GMainContext *context) +{ + qemu_mutex_lock(&task->mutex); + if (task->context) { + g_main_context_unref(task->context); + } + if (context) { + g_main_context_ref(task->context); + task->context =3D context; + } + if (task->idle_source) { + /* + * We have had an idle job on the old context. Firstly delete + * the old one, then create a new one on the new context. + */ + qio_task_thread_create_complete_job(task); + } + qemu_mutex_unlock(&task->mutex); +} --=20 2.14.3