From nobody Sun Feb 8 12:37:28 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) client-ip=205.139.110.120; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-1.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by mx.zohomail.com with SMTPS id 15809231590641021.4368576872577; Wed, 5 Feb 2020 09:19:19 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-238-4DoTYfZ6NsC7W8JMR2h4kA-1; Wed, 05 Feb 2020 12:19:11 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2702C1416; Wed, 5 Feb 2020 17:19:06 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E9D8089E81; Wed, 5 Feb 2020 17:19:05 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id AC0AC85CF7; Wed, 5 Feb 2020 17:19:05 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 015HJ4lG015875 for ; Wed, 5 Feb 2020 12:19:04 -0500 Received: by smtp.corp.redhat.com (Postfix) id 05DED857A8; Wed, 5 Feb 2020 17:19:04 +0000 (UTC) Received: from domokun.gsslab.fab.redhat.com (unknown [10.33.8.110]) by smtp.corp.redhat.com (Postfix) with ESMTP id 48A52857B7; Wed, 5 Feb 2020 17:19:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1580923157; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=mXxO8A+9ekGdsGQOs3a94l38DadcqT7kWXuJooluVAg=; b=O25widbK1bAIwv8+QxgnEAOGBPuiHcw0QtQBF2G80MnasJx/4HDIL00FhYrAhjwwQRmJBT HOGS42vo7AJnRijR80tqPZV3DoPgbtMqUfwNhufTYFsPECdKSIE77lunMsHN6LvUS843HI GdR9ImvjjAEwBn40ngcDAPrShqKKgEY= From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Subject: [libvirt PATCH v3 1/7] tools: rewrite interactive job monitoring logic Date: Wed, 5 Feb 2020 17:18:52 +0000 Message-Id: <20200205171858.2694632-2-berrange@redhat.com> In-Reply-To: <20200205171858.2694632-1-berrange@redhat.com> References: <20200205171858.2694632-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-MC-Unique: 4DoTYfZ6NsC7W8JMR2h4kA-1 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" For long running jobs (save, managed save, dump & live migrate) virsh runs a background thread for executing the job and then has the main thread catch Ctrl-C for graceful shutdown, as well as displaying progress info. The monitoring code is written using poll, with a pipe used to get the completion status from the thread. Using a pipe and poll is problematic for Windows portability. This rewrites the code to use a GMainLoop instance for monitoring stdin and doing progress updates. The use of a pipe is entirely eliminated, instead there is just a shared variable between both threads containing the job completion status. No mutex locking is used because the background thread writes to the variable only when the main loop is still running, while the foreground thread only reads it after the main loop has exited. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Pavel Hrdina --- tools/virsh-domain.c | 388 +++++++++++++++++++++++++------------------ tools/virsh.h | 3 +- 2 files changed, 232 insertions(+), 159 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 781463f0e2..bf828c90c4 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -23,7 +23,6 @@ #include "virsh-util.h" =20 #include -#include #include #include =20 @@ -4224,7 +4223,6 @@ doSave(void *opaque) virshCtrlData *data =3D opaque; vshControl *ctl =3D data->ctl; const vshCmd *cmd =3D data->cmd; - char ret =3D '1'; virDomainPtr dom =3D NULL; const char *name =3D NULL; const char *to =3D NULL; @@ -4269,7 +4267,7 @@ doSave(void *opaque) goto out; } =20 - ret =3D '0'; + data->ret =3D 0; =20 out: #ifndef WIN32 @@ -4278,18 +4276,126 @@ doSave(void *opaque) #endif /* !WIN32 */ virshDomainFree(dom); VIR_FREE(xml); - ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); + g_main_loop_quit(data->eventLoop); } =20 typedef void (*jobWatchTimeoutFunc)(vshControl *ctl, virDomainPtr dom, void *opaque); =20 -static bool +struct virshWatchData { + vshControl *ctl; + virDomainPtr dom; + jobWatchTimeoutFunc timeout_func; + void *opaque; + const char *label; + GIOChannel *stdin_ioc; + bool jobStarted; + bool verbose; +}; + +static gboolean +virshWatchTimeout(gpointer opaque) +{ + struct virshWatchData *data =3D opaque; + + /* suspend the domain when migration timeouts. */ + vshDebug(data->ctl, VSH_ERR_DEBUG, "watchJob: timeout\n"); + if (data->timeout_func) + (data->timeout_func)(data->ctl, data->dom, data->opaque); + + return G_SOURCE_REMOVE; +} + + +static gboolean +virshWatchProgress(gpointer opaque) +{ + struct virshWatchData *data =3D opaque; + virDomainJobInfo jobinfo; +#ifndef WIN32 + sigset_t sigmask, oldsigmask; + int ret; + + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGINT); + + vshDebug(data->ctl, VSH_ERR_DEBUG, "%s", + "watchJob: progress update\n"); + pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask); +#endif /* !WIN32 */ + ret =3D virDomainGetJobInfo(data->dom, &jobinfo); +#ifndef WIN32 + pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); +#endif /* !WIN32 */ + + if (ret =3D=3D 0) { + if (data->verbose && jobinfo.dataTotal > 0) + virshPrintJobProgress(data->label, jobinfo.dataRemaining, + jobinfo.dataTotal); + + if (!data->jobStarted && + (jobinfo.type =3D=3D VIR_DOMAIN_JOB_BOUNDED || + jobinfo.type =3D=3D VIR_DOMAIN_JOB_UNBOUNDED)) { + vshTTYDisableInterrupt(data->ctl); + data->jobStarted =3D true; + + if (!data->verbose) { + vshDebug(data->ctl, VSH_ERR_DEBUG, + "watchJob: job started, disabling callback\n"); + return G_SOURCE_REMOVE; + } + } + } else { + vshResetLibvirtError(); + } + + return G_SOURCE_CONTINUE; +} + + +static gboolean +virshWatchInterrupt(GIOChannel *source G_GNUC_UNUSED, + GIOCondition condition, + gpointer opaque) +{ + struct virshWatchData *data =3D opaque; + char retchar; + gsize nread =3D 0; + + vshDebug(data->ctl, VSH_ERR_DEBUG, + "watchJob: stdin data %d\n", condition); + if (condition & G_IO_IN) { + g_io_channel_read_chars(data->stdin_ioc, + &retchar, + sizeof(retchar), + &nread, + NULL); + + vshDebug(data->ctl, VSH_ERR_DEBUG, + "watchJob: got %zu characters\n", nread); + if (nread =3D=3D 1 && + vshTTYIsInterruptCharacter(data->ctl, retchar)) { + virDomainAbortJob(data->dom); + return G_SOURCE_REMOVE; + } + } + + if (condition & (G_IO_ERR | G_IO_HUP)) { + virDomainAbortJob(data->dom); + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + + +static void virshWatchJob(vshControl *ctl, virDomainPtr dom, bool verbose, - int pipe_fd, - int timeout_ms, + GMainLoop *eventLoop, + int *job_err, + int timeout_secs, jobWatchTimeoutFunc timeout_func, void *opaque, const char *label) @@ -4297,22 +4403,22 @@ virshWatchJob(vshControl *ctl, #ifndef WIN32 struct sigaction sig_action; struct sigaction old_sig_action; - sigset_t sigmask, oldsigmask; #endif /* !WIN32 */ - struct pollfd pollfd[2] =3D {{.fd =3D pipe_fd, .events =3D POLLIN, .re= vents =3D 0}, - {.fd =3D STDIN_FILENO, .events =3D POLLIN, = .revents =3D 0}}; - unsigned long long start_us, curr_us; - virDomainJobInfo jobinfo; - int ret =3D -1; - char retchar; - bool functionReturn =3D false; - bool jobStarted =3D false; - nfds_t npollfd =3D 2; + g_autoptr(GSource) timeout_src =3D NULL; + g_autoptr(GSource) progress_src =3D NULL; + g_autoptr(GSource) stdin_src =3D NULL; + struct virshWatchData data =3D { + .ctl =3D ctl, + .dom =3D dom, + .timeout_func =3D timeout_func, + .opaque =3D opaque, + .label =3D label, + .stdin_ioc =3D NULL, + .jobStarted =3D false, + .verbose =3D verbose, + }; =20 #ifndef WIN32 - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGINT); - intCaught =3D 0; sig_action.sa_sigaction =3D virshCatchInt; sig_action.sa_flags =3D SA_SIGINFO; @@ -4321,98 +4427,77 @@ virshWatchJob(vshControl *ctl, #endif /* !WIN32 */ =20 /* don't poll on STDIN if we are not using a terminal */ - if (!vshTTYAvailable(ctl)) - npollfd =3D 1; - - start_us =3D g_get_real_time(); - while (1) { - ret =3D poll((struct pollfd *)&pollfd, npollfd, 500); - if (ret > 0) { - if (pollfd[1].revents & POLLIN && - saferead(STDIN_FILENO, &retchar, sizeof(retchar)) > 0) { - if (vshTTYIsInterruptCharacter(ctl, retchar)) - virDomainAbortJob(dom); - continue; - } - - if (pollfd[0].revents & POLLIN && - saferead(pipe_fd, &retchar, sizeof(retchar)) > 0 && - retchar =3D=3D '0') { - if (verbose) { - /* print [100 %] */ - virshPrintJobProgress(label, 0, 1); - } - break; - } - goto cleanup; - } - - if (ret < 0) { - if (errno =3D=3D EINTR) { - if (intCaught) { - virDomainAbortJob(dom); - intCaught =3D 0; - } - continue; - } - goto cleanup; - } - - curr_us =3D g_get_real_time(); - if (timeout_ms && ((curr_us - start_us)/1000) > timeout_ms) { - /* suspend the domain when migration timeouts. */ - vshDebug(ctl, VSH_ERR_DEBUG, "%s timeout", label); - if (timeout_func) - (timeout_func)(ctl, dom, opaque); - timeout_ms =3D 0; - } - - if (verbose || !jobStarted) { -#ifndef WIN32 - pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask); -#endif /* !WIN32 */ - ret =3D virDomainGetJobInfo(dom, &jobinfo); -#ifndef WIN32 - pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); -#endif /* !WIN32 */ - if (ret =3D=3D 0) { - if (verbose && jobinfo.dataTotal > 0) - virshPrintJobProgress(label, jobinfo.dataRemaining, - jobinfo.dataTotal); - - if (!jobStarted && - (jobinfo.type =3D=3D VIR_DOMAIN_JOB_BOUNDED || - jobinfo.type =3D=3D VIR_DOMAIN_JOB_UNBOUNDED)) { - vshTTYDisableInterrupt(ctl); - jobStarted =3D true; - } - } else { - vshResetLibvirtError(); - } - } + if (vshTTYAvailable(ctl)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s", + "watchJob: on TTY, enabling Ctrl-c processing\n"); +#ifdef WIN32 + data.stdin_ioc =3D g_io_channel_win32_new_fd(STDIN_FILENO); +#else + data.stdin_ioc =3D g_io_channel_unix_new(STDIN_FILENO); +#endif + stdin_src =3D g_io_create_watch(data.stdin_ioc, G_IO_IN); + g_source_set_callback(stdin_src, + (GSourceFunc)virshWatchInterrupt, + &data, NULL); + g_source_attach(stdin_src, + g_main_loop_get_context(eventLoop)); } =20 - functionReturn =3D true; + if (timeout_secs) { + vshDebug(ctl, VSH_ERR_DEBUG, + "watchJob: setting timeout of %d secs\n", timeout_secs); + timeout_src =3D g_timeout_source_new_seconds(timeout_secs); + g_source_set_callback(timeout_src, + virshWatchTimeout, + &data, NULL); + g_source_attach(timeout_src, + g_main_loop_get_context(eventLoop)); + } + + progress_src =3D g_timeout_source_new(500); + g_source_set_callback(progress_src, + virshWatchProgress, + &data, NULL); + g_source_attach(progress_src, + g_main_loop_get_context(eventLoop)); + + g_main_loop_run(eventLoop); + + vshDebug(ctl, VSH_ERR_DEBUG, + "watchJob: job done, status %d\n", *job_err); + if (*job_err =3D=3D 0 && verbose) /* print [100 %] */ + virshPrintJobProgress(label, 0, 1); + + if (timeout_src) + g_source_destroy(timeout_src); + g_source_destroy(progress_src); + if (stdin_src) + g_source_destroy(stdin_src); =20 - cleanup: #ifndef WIN32 sigaction(SIGINT, &old_sig_action, NULL); #endif /* !WIN32 */ vshTTYRestore(ctl); - return functionReturn; + if (data.stdin_ioc) + g_io_channel_unref(data.stdin_ioc); } =20 static bool cmdSave(vshControl *ctl, const vshCmd *cmd) { - bool ret =3D false; virDomainPtr dom =3D NULL; - int p[2] =3D {-1. -1}; virThread workerThread; bool verbose =3D false; - virshCtrlData data; const char *to =3D NULL; const char *name =3D NULL; + g_autoptr(GMainContext) eventCtxt =3D g_main_context_new(); + g_autoptr(GMainLoop) eventLoop =3D g_main_loop_new(eventCtxt, FALSE); + virshCtrlData data =3D { + .ctl =3D ctl, + .cmd =3D cmd, + .eventLoop =3D eventLoop, + .ret =3D -1, + }; =20 if (!(dom =3D virshCommandOptDomain(ctl, cmd, &name))) return false; @@ -4423,29 +4508,23 @@ cmdSave(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "verbose")) verbose =3D true; =20 - if (virPipeQuiet(p) < 0) - goto cleanup; - - data.ctl =3D ctl; - data.cmd =3D cmd; - data.writefd =3D p[1]; - if (virThreadCreate(&workerThread, true, doSave, &data) < 0) goto cleanup; =20 - ret =3D virshWatchJob(ctl, dom, verbose, p[0], 0, NULL, NULL, _("Save"= )); + virshWatchJob(ctl, dom, verbose, eventLoop, + &data.ret, 0, NULL, NULL, _("Save")); =20 virThreadJoin(&workerThread); =20 - if (ret) + if (!data.ret) vshPrintExtra(ctl, _("\nDomain %s saved to %s\n"), name, to); =20 cleanup: virshDomainFree(dom); - return ret; + return !data.ret; } =20 /* @@ -4674,7 +4753,6 @@ static const vshCmdOptDef opts_managedsave[] =3D { static void doManagedsave(void *opaque) { - char ret =3D '1'; virshCtrlData *data =3D opaque; vshControl *ctl =3D data->ctl; const vshCmd *cmd =3D data->cmd; @@ -4705,26 +4783,31 @@ doManagedsave(void *opaque) goto out; } =20 - ret =3D '0'; + data->ret =3D 0; out: #ifndef WIN32 pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); out_sig: #endif /* !WIN32 */ virshDomainFree(dom); - ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); + g_main_loop_quit(data->eventLoop); } =20 static bool cmdManagedSave(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom; - int p[2] =3D { -1, -1}; - bool ret =3D false; bool verbose =3D false; const char *name =3D NULL; - virshCtrlData data; virThread workerThread; + g_autoptr(GMainContext) eventCtxt =3D g_main_context_new(); + g_autoptr(GMainLoop) eventLoop =3D g_main_loop_new(eventCtxt, FALSE); + virshCtrlData data =3D { + .ctl =3D ctl, + .cmd =3D cmd, + .eventLoop =3D eventLoop, + .ret =3D -1, + }; =20 if (!(dom =3D virshCommandOptDomain(ctl, cmd, &name))) return false; @@ -4732,32 +4815,23 @@ cmdManagedSave(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "verbose")) verbose =3D true; =20 - if (virPipeQuiet(p) < 0) - goto cleanup; - - data.ctl =3D ctl; - data.cmd =3D cmd; - data.writefd =3D p[1]; - if (virThreadCreate(&workerThread, true, doManagedsave, &data) < 0) goto cleanup; =20 - ret =3D virshWatchJob(ctl, dom, verbose, p[0], 0, - NULL, NULL, _("Managedsave")); + virshWatchJob(ctl, dom, verbose, eventLoop, + &data.ret, 0, NULL, NULL, _("Managedsave")); =20 virThreadJoin(&workerThread); =20 - if (ret) + if (!data.ret) vshPrintExtra(ctl, _("\nDomain %s state saved by libvirt\n"), name= ); =20 cleanup: virshDomainFree(dom); - VIR_FORCE_CLOSE(p[0]); - VIR_FORCE_CLOSE(p[1]); - return ret; + return !data.ret; } =20 /* @@ -5438,20 +5512,27 @@ doDump(void *opaque) #endif /* !WIN32 */ if (dom) virshDomainFree(dom); - ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); + data->ret =3D ret; + g_main_loop_quit(data->eventLoop); } =20 static bool cmdDump(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom; - int p[2] =3D { -1, -1}; bool ret =3D false; bool verbose =3D false; const char *name =3D NULL; const char *to =3D NULL; - virshCtrlData data; virThread workerThread; + g_autoptr(GMainContext) eventCtxt =3D g_main_context_new(); + g_autoptr(GMainLoop) eventLoop =3D g_main_loop_new(eventCtxt, FALSE); + virshCtrlData data =3D { + .ctl =3D ctl, + .cmd =3D cmd, + .eventLoop =3D eventLoop, + .ret =3D -1, + }; =20 if (!(dom =3D virshCommandOptDomain(ctl, cmd, &name))) return false; @@ -5462,31 +5543,23 @@ cmdDump(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "verbose")) verbose =3D true; =20 - if (virPipeQuiet(p) < 0) - goto cleanup; - - data.ctl =3D ctl; - data.cmd =3D cmd; - data.writefd =3D p[1]; - if (virThreadCreate(&workerThread, true, doDump, &data) < 0) goto cleanup; =20 - ret =3D virshWatchJob(ctl, dom, verbose, p[0], 0, NULL, NULL, _("Dump"= )); + virshWatchJob(ctl, dom, verbose, eventLoop, + &data.ret, 0, NULL, NULL, _("Dump")); =20 virThreadJoin(&workerThread); =20 - if (ret) + if (!ret) vshPrintExtra(ctl, _("\nDomain %s dumped to %s\n"), name, to); =20 cleanup: virshDomainFree(dom); - VIR_FORCE_CLOSE(p[0]); - VIR_FORCE_CLOSE(p[1]); - return ret; + return !ret; } =20 static const vshCmdInfo info_screenshot[] =3D { @@ -10916,7 +10989,8 @@ doMigrate(void *opaque) #endif /* !WIN32 */ virTypedParamsFree(params, nparams); virshDomainFree(dom); - ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); + data->ret =3D ret; + g_main_loop_quit(data->eventLoop); return; =20 save_error: @@ -10976,16 +11050,22 @@ static bool cmdMigrate(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom =3D NULL; - int p[2] =3D {-1, -1}; virThread workerThread; bool verbose =3D false; - bool functionReturn =3D false; - int timeout =3D 0; + unsigned int timeout =3D 0; virshMigrateTimeoutAction timeoutAction =3D VIRSH_MIGRATE_TIMEOUT_DEFA= ULT; bool live_flag =3D false; - virshCtrlData data =3D { .dconn =3D NULL }; virshControlPtr priv =3D ctl->privData; int iterEvent =3D -1; + g_autoptr(GMainContext) eventCtxt =3D g_main_context_new(); + g_autoptr(GMainLoop) eventLoop =3D g_main_loop_new(eventCtxt, FALSE); + virshCtrlData data =3D { + .dconn =3D NULL, + .ctl =3D ctl, + .cmd =3D cmd, + .eventLoop =3D eventLoop, + .ret =3D -1, + }; =20 VSH_EXCLUSIVE_OPTIONS("live", "offline"); VSH_EXCLUSIVE_OPTIONS("timeout-suspend", "timeout-postcopy"); @@ -11002,7 +11082,7 @@ cmdMigrate(vshControl *ctl, const vshCmd *cmd) =20 if (vshCommandOptBool(cmd, "live")) live_flag =3D true; - if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) { + if (vshCommandOptUInt(ctl, cmd, "timeout", &timeout) < 0) { goto cleanup; } else if (timeout > 0 && !live_flag) { vshError(ctl, "%s", @@ -11033,13 +11113,6 @@ cmdMigrate(vshControl *ctl, const vshCmd *cmd) goto cleanup; } =20 - if (virPipeQuiet(p) < 0) - goto cleanup; - - data.ctl =3D ctl; - data.cmd =3D cmd; - data.writefd =3D p[1]; - if (vshCommandOptBool(cmd, "p2p") || vshCommandOptBool(cmd, "direct"))= { data.dconn =3D NULL; } else { @@ -11062,9 +11135,10 @@ cmdMigrate(vshControl *ctl, const vshCmd *cmd) doMigrate, &data) < 0) goto cleanup; - functionReturn =3D virshWatchJob(ctl, dom, verbose, p[0], timeout, - virshMigrateTimeout, - &timeoutAction, _("Migration")); + virshWatchJob(ctl, dom, verbose, eventLoop, + &data.ret, timeout, + virshMigrateTimeout, + &timeoutAction, _("Migration")); =20 virThreadJoin(&workerThread); =20 @@ -11074,9 +11148,7 @@ cmdMigrate(vshControl *ctl, const vshCmd *cmd) if (iterEvent !=3D -1) virConnectDomainEventDeregisterAny(priv->conn, iterEvent); virshDomainFree(dom); - VIR_FORCE_CLOSE(p[0]); - VIR_FORCE_CLOSE(p[1]); - return functionReturn; + return !data.ret; } =20 /* diff --git a/tools/virsh.h b/tools/virsh.h index fa9e54b1d1..ef18c7f421 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -159,7 +159,8 @@ struct _virshControl { struct _virshCtrlData { vshControl *ctl; const vshCmd *cmd; - int writefd; + GMainLoop *eventLoop; + int ret; virConnectPtr dconn; }; =20 --=20 2.24.1