From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3C8F4ECAAD8 for ; Thu, 22 Sep 2022 20:02:39 +0000 (UTC) Received: from localhost ([::1]:49580 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1obSP8-00030Y-6D for qemu-devel@archiver.kernel.org; Thu, 22 Sep 2022 16:02:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:43190) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1obSMZ-0001Gj-P1 for qemu-devel@nongnu.org; Thu, 22 Sep 2022 15:59:59 -0400 Received: from mail-lf1-x12e.google.com ([2a00:1450:4864:20::12e]:35463) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1obSMX-0004Kw-0q for qemu-devel@nongnu.org; Thu, 22 Sep 2022 15:59:59 -0400 Received: by mail-lf1-x12e.google.com with SMTP id z25so16496725lfr.2 for ; Thu, 22 Sep 2022 12:59:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date; bh=oSk4ZDWorQ44VHgGGPgXsS90XxbqTU0tpElIMhRbrHM=; b=KN5TDS9HkMzd83TogS+0cTk2r9c5+OcExSM4WAaf9/tI97IP5WsxKrV7Tl5m75aXlE zA7Y+BWhmQbUNjKHdaHCWDttESlSUs7ex31pCmpQEK0b1XsD5DDXdhrz5hLk2YxjmHc2 ihahLgcyZM4JjzVS7rL9Wgcd5fNMU8ioYDTOE3gZFUmFgHhMNX68wQvZRwPLHCYc/0X+ Hyyv9ia93kBAxUnf7kM+5ABJp2A/37sWsXPoi2Un3oxnVenMJnRZfTAHtbfwigKage5B 0Mi6hGgjnrYq5vA3LdkKBc5CZ7xGUNoVjJRGZHAlvDIC3fyNWUzONfnvFU9JnZJIvJEI tP3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date; bh=oSk4ZDWorQ44VHgGGPgXsS90XxbqTU0tpElIMhRbrHM=; b=hwX4W+Az6VX6Lmiee9ddy94HU1I+jh8QlC0Zc3bk3aHh++h7141b8T+c6LfKAH+STv 7htB1szoLnosJLQKJmQY1sjECcFeRkzHe8GfFJiQ/iOhVYIuaJkHTtqsIKXn3VdNAtjg 3cXlf8snvDogqr1T2kJhsPnS/6MVyHYomsx96djb/Ed4xJxwDHDydktm/js8Q3qDNeUs QDKvdSwWMQmidHkeI22SIfAE5VHWXkaQwL/8NhnetCxCba4u0ZDLeank1C4hv48KRkr8 jz/yC4PhYpnCTDNzGIoVLd/WNqoalSvvV3SriTPAtpsihJrgE04vcPPTAegSuFMYAsDU JceA== X-Gm-Message-State: ACrzQf15CFMa69FL2R5swMISJoRRme/9KS3tQh5iOxKY7N3Ia+bTAeW4 XxnuH1hK4gWMx98zbuxMKldP3igkXJHl6E/eRyk= X-Google-Smtp-Source: AMsMyM5HLkXCW+ePoK3LpbH4OPNV7O0UBhByKqYYWcd3xlJtbisVn+kdoRV9EMlbUB9Znhp+FsD3qVqzdahwYANyUY0= X-Received: by 2002:a05:6512:3e10:b0:498:f317:e57e with SMTP id i16-20020a0565123e1000b00498f317e57emr1994809lfv.328.1663876795005; Thu, 22 Sep 2022 12:59:55 -0700 (PDT) MIME-Version: 1.0 References: <20220920103159.1865256-1-bmeng.cn@gmail.com> <20220920103159.1865256-20-bmeng.cn@gmail.com> In-Reply-To: <20220920103159.1865256-20-bmeng.cn@gmail.com> From: =?UTF-8?B?TWFyYy1BbmRyw6kgTHVyZWF1?= Date: Thu, 22 Sep 2022 21:59:43 +0200 Message-ID: Subject: Re: [PATCH v2 19/39] tests/qtest: Support libqtest to build and run on Windows To: Bin Meng Cc: qemu-devel@nongnu.org, Bin Meng , Xuzhou Cheng , Laurent Vivier , Paolo Bonzini , Thomas Huth Content-Type: multipart/alternative; boundary="00000000000050feac05e94981d5" Received-SPF: pass client-ip=2a00:1450:4864:20::12e; envelope-from=marcandre.lureau@gmail.com; helo=mail-lf1-x12e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --00000000000050feac05e94981d5 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi On Tue, Sep 20, 2022 at 1:36 PM Bin Meng wrote: > From: Bin Meng > > At present the libqtest codes were written to depend on several > POSIX APIs, including fork(), kill() and waitpid(). Unfortunately > these APIs are not available on Windows. > > This commit implements the corresponding functionalities using > win32 native APIs. With this change, all qtest cases can build > successfully on a Windows host, and we can start qtest testing > on Windows now. > > Signed-off-by: Xuzhou Cheng > Signed-off-by: Bin Meng > lgtm Reviewed-by: Marc-Andr=C3=A9 Lureau > --- > > Changes in v2: > - Move the enabling of building qtests on Windows to a separate > patch to keep bisectablity > - Call socket_init() unconditionally > - Add a missing CloseHandle() call > > tests/qtest/libqtest.c | 98 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 96 insertions(+), 2 deletions(-) > > diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c > index f46a21fa45..5d15e39289 100644 > --- a/tests/qtest/libqtest.c > +++ b/tests/qtest/libqtest.c > @@ -16,9 +16,11 @@ > > #include "qemu/osdep.h" > > +#ifndef _WIN32 > #include > #include > #include > +#endif /* _WIN32 */ > #ifdef __linux__ > #include > #endif /* __linux__ */ > @@ -27,6 +29,7 @@ > #include "libqmp.h" > #include "qemu/ctype.h" > #include "qemu/cutils.h" > +#include "qemu/sockets.h" > #include "qapi/qmp/qdict.h" > #include "qapi/qmp/qjson.h" > #include "qapi/qmp/qlist.h" > @@ -35,6 +38,16 @@ > #define MAX_IRQ 256 > #define SOCKET_TIMEOUT 50 > > +#ifndef _WIN32 > +# define CMD_EXEC "exec " > +# define DEV_STDERR "/dev/fd/2" > +# define DEV_NULL "/dev/null" > +#else > +# define CMD_EXEC "" > +# define DEV_STDERR "2" > +# define DEV_NULL "nul" > +#endif > + > typedef void (*QTestSendFn)(QTestState *s, const char *buf); > typedef void (*ExternalSendFn)(void *s, const char *buf); > typedef GString* (*QTestRecvFn)(QTestState *); > @@ -66,6 +79,9 @@ struct QTestState > }; > > static GHookList abrt_hooks; > +#ifdef _WIN32 > +typedef void (*sighandler_t)(int); > +#endif > static sighandler_t sighandler_old; > > static int qtest_query_target_endianness(QTestState *s); > @@ -118,10 +134,19 @@ bool qtest_probe_child(QTestState *s) > pid_t pid =3D s->qemu_pid; > > if (pid !=3D -1) { > +#ifndef _WIN32 > pid =3D waitpid(pid, &s->wstatus, WNOHANG); > if (pid =3D=3D 0) { > return true; > } > +#else > + DWORD exit_code; > + GetExitCodeProcess((HANDLE)pid, &exit_code); > + if (exit_code =3D=3D STILL_ACTIVE) { > + return true; > + } > + CloseHandle((HANDLE)pid); > +#endif > s->qemu_pid =3D -1; > } > return false; > @@ -135,13 +160,23 @@ void qtest_set_expected_status(QTestState *s, int > status) > void qtest_kill_qemu(QTestState *s) > { > pid_t pid =3D s->qemu_pid; > +#ifndef _WIN32 > int wstatus; > +#else > + DWORD ret, exit_code; > +#endif > > /* Skip wait if qtest_probe_child already reaped. */ > if (pid !=3D -1) { > +#ifndef _WIN32 > kill(pid, SIGTERM); > TFR(pid =3D waitpid(s->qemu_pid, &s->wstatus, 0)); > assert(pid =3D=3D s->qemu_pid); > +#else > + TerminateProcess((HANDLE)pid, s->expected_status); > + ret =3D WaitForSingleObject((HANDLE)pid, INFINITE); > + assert(ret =3D=3D WAIT_OBJECT_0); > +#endif > s->qemu_pid =3D -1; > } > > @@ -149,6 +184,7 @@ void qtest_kill_qemu(QTestState *s) > * Check whether qemu exited with expected exit status; anything els= e > is > * fishy and should be logged with as much detail as possible. > */ > +#ifndef _WIN32 > wstatus =3D s->wstatus; > if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) !=3D s->expected_stat= us) > { > fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU " > @@ -165,6 +201,16 @@ void qtest_kill_qemu(QTestState *s) > __FILE__, __LINE__, sig, signame, dump); > abort(); > } > +#else > + GetExitCodeProcess((HANDLE)pid, &exit_code); > + CloseHandle((HANDLE)pid); > + if (exit_code !=3D s->expected_status) { > + fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU " > + "process but encountered exit status %ld (expected %d)\n= ", > + __FILE__, __LINE__, exit_code, s->expected_status); > + abort(); > + } > +#endif > } > > static void kill_qemu_hook_func(void *s) > @@ -243,6 +289,38 @@ static const char *qtest_qemu_binary(void) > return qemu_bin; > } > > +#ifdef _WIN32 > +static pid_t qtest_create_process(char *cmd) > +{ > + STARTUPINFO si; > + PROCESS_INFORMATION pi; > + BOOL ret; > + > + ZeroMemory(&si, sizeof(si)); > + si.cb =3D sizeof(si); > + ZeroMemory(&pi, sizeof(pi)); > + > + ret =3D CreateProcess(NULL, /* module name */ > + cmd, /* command line */ > + NULL, /* process handle not inheritable */ > + NULL, /* thread handle not inheritable */ > + FALSE, /* set handle inheritance to FALSE */ > + 0, /* No creation flags */ > + NULL, /* use parent's environment block */ > + NULL, /* use parent's starting directory */ > + &si, /* pointer to STARTUPINFO structure */ > + &pi /* pointer to PROCESS_INFORMATION > structure */ > + ); > + if (ret =3D=3D 0) { > + fprintf(stderr, "%s:%d: unable to create a new process (%s)\n", > + __FILE__, __LINE__, strerror(GetLastError())); > + abort(); > + } > + > + return (pid_t)pi.hProcess; > +} > +#endif /* _WIN32 */ > + > QTestState *qtest_init_without_qmp_handshake(const char *extra_args) > { > QTestState *s; > @@ -270,6 +348,7 @@ QTestState *qtest_init_without_qmp_handshake(const > char *extra_args) > unlink(socket_path); > unlink(qmp_socket_path); > > + socket_init(); > sock =3D init_socket(socket_path); > qmpsock =3D init_socket(qmp_socket_path); > > @@ -278,7 +357,7 @@ QTestState *qtest_init_without_qmp_handshake(const > char *extra_args) > > qtest_add_abrt_handler(kill_qemu_hook_func, s); > > - command =3D g_strdup_printf("exec %s %s" > + command =3D g_strdup_printf(CMD_EXEC "%s %s" > "-qtest unix:%s " > "-qtest-log %s " > "-chardev socket,path=3D%s,id=3Dchar0 " > @@ -287,7 +366,7 @@ QTestState *qtest_init_without_qmp_handshake(const > char *extra_args) > "%s" > " -accel qtest", > qemu_binary, tracearg, socket_path, > - getenv("QTEST_LOG") ? "/dev/fd/2" : > "/dev/null", > + getenv("QTEST_LOG") ? DEV_STDERR : DEV_NUL= L, > qmp_socket_path, > extra_args ?: ""); > > @@ -296,6 +375,7 @@ QTestState *qtest_init_without_qmp_handshake(const > char *extra_args) > s->pending_events =3D NULL; > s->wstatus =3D 0; > s->expected_status =3D 0; > +#ifndef _WIN32 > s->qemu_pid =3D fork(); > if (s->qemu_pid =3D=3D 0) { > #ifdef __linux__ > @@ -318,6 +398,9 @@ QTestState *qtest_init_without_qmp_handshake(const > char *extra_args) > execlp("/bin/sh", "sh", "-c", command, NULL); > exit(1); > } > +#else > + s->qemu_pid =3D qtest_create_process(command); > +#endif /* _WIN32 */ > > g_free(command); > s->fd =3D socket_accept(sock); > @@ -336,9 +419,19 @@ QTestState *qtest_init_without_qmp_handshake(const > char *extra_args) > s->irq_level[i] =3D false; > } > > + /* > + * Stopping QEMU for debugging is not supported on Windows. > + * > + * Using DebugActiveProcess() API can suspend the QEMU process, > + * but gdb cannot attach to the process. Using the undocumented > + * NtSuspendProcess() can suspend the QEMU process and gdb can > + * attach to the process, but gdb cannot resume it. > + */ > +#ifndef _WIN32 > if (getenv("QTEST_STOP")) { > kill(s->qemu_pid, SIGSTOP); > } > +#endif > > /* ask endianness of the target */ > > @@ -392,6 +485,7 @@ QTestState *qtest_init_with_serial(const char > *extra_args, int *sock_fd) > g_assert_true(sock_dir !=3D NULL); > sock_path =3D g_strdup_printf("%s/sock", sock_dir); > > + socket_init(); > sock_fd_init =3D init_socket(sock_path); > > qts =3D qtest_initf("-chardev socket,id=3Ds0,path=3D%s -serial chard= ev:s0 > %s", > -- > 2.34.1 > > > --=20 Marc-Andr=C3=A9 Lureau --00000000000050feac05e94981d5 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi

On Tue, Sep 20, 2022 at 1:36 PM Bin= Meng <bmeng.cn@gmail.com> = wrote:
From: Bin= Meng <bin.m= eng@windriver.com>

At present the libqtest codes were written to depend on several
POSIX APIs, including fork(), kill() and waitpid(). Unfortunately
these APIs are not available on Windows.

This commit implements the corresponding functionalities using
win32 native APIs. With this change, all qtest cases can build
successfully on a Windows host, and we can start qtest testing
on Windows now.

Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

=
lgtm
Reviewed-by: Marc-Andr=C3=A9 Lureau <marcandre.lureau@redhat.com>
=C2=A0
---

Changes in v2:
- Move the enabling of building qtests on Windows to a separate
=C2=A0 patch to keep bisectablity
- Call socket_init() unconditionally
- Add a missing CloseHandle() call

=C2=A0tests/qtest/libqtest.c | 98 +++++++++++++++++++++++++++++++++++++++++= -
=C2=A01 file changed, 96 insertions(+), 2 deletions(-)

diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index f46a21fa45..5d15e39289 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -16,9 +16,11 @@

=C2=A0#include "qemu/osdep.h"

+#ifndef _WIN32
=C2=A0#include <sys/socket.h>
=C2=A0#include <sys/wait.h>
=C2=A0#include <sys/un.h>
+#endif /* _WIN32 */
=C2=A0#ifdef __linux__
=C2=A0#include <sys/prctl.h>
=C2=A0#endif /* __linux__ */
@@ -27,6 +29,7 @@
=C2=A0#include "libqmp.h"
=C2=A0#include "qemu/ctype.h"
=C2=A0#include "qemu/cutils.h"
+#include "qemu/sockets.h"
=C2=A0#include "qapi/qmp/qdict.h"
=C2=A0#include "qapi/qmp/qjson.h"
=C2=A0#include "qapi/qmp/qlist.h"
@@ -35,6 +38,16 @@
=C2=A0#define MAX_IRQ 256
=C2=A0#define SOCKET_TIMEOUT 50

+#ifndef _WIN32
+# define CMD_EXEC=C2=A0 =C2=A0"exec "
+# define DEV_STDERR "/dev/fd/2"
+# define DEV_NULL=C2=A0 =C2=A0"/dev/null"
+#else
+# define CMD_EXEC=C2=A0 =C2=A0""
+# define DEV_STDERR "2"
+# define DEV_NULL=C2=A0 =C2=A0"nul"
+#endif
+
=C2=A0typedef void (*QTestSendFn)(QTestState *s, const char *buf);
=C2=A0typedef void (*ExternalSendFn)(void *s, const char *buf);
=C2=A0typedef GString* (*QTestRecvFn)(QTestState *);
@@ -66,6 +79,9 @@ struct QTestState
=C2=A0};

=C2=A0static GHookList abrt_hooks;
+#ifdef _WIN32
+typedef void (*sighandler_t)(int);
+#endif
=C2=A0static sighandler_t sighandler_old;

=C2=A0static int qtest_query_target_endianness(QTestState *s);
@@ -118,10 +134,19 @@ bool qtest_probe_child(QTestState *s)
=C2=A0 =C2=A0 =C2=A0pid_t pid =3D s->qemu_pid;

=C2=A0 =C2=A0 =C2=A0if (pid !=3D -1) {
+#ifndef _WIN32
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pid =3D waitpid(pid, &s->wstatus, = WNOHANG);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (pid =3D=3D 0) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return true;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+#else
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 DWORD exit_code;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 GetExitCodeProcess((HANDLE)pid, &exit_code= );
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (exit_code =3D=3D STILL_ACTIVE) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return true;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 CloseHandle((HANDLE)pid);
+#endif
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->qemu_pid =3D -1;
=C2=A0 =C2=A0 =C2=A0}
=C2=A0 =C2=A0 =C2=A0return false;
@@ -135,13 +160,23 @@ void qtest_set_expected_status(QTestState *s, int sta= tus)
=C2=A0void qtest_kill_qemu(QTestState *s)
=C2=A0{
=C2=A0 =C2=A0 =C2=A0pid_t pid =3D s->qemu_pid;
+#ifndef _WIN32
=C2=A0 =C2=A0 =C2=A0int wstatus;
+#else
+=C2=A0 =C2=A0 DWORD ret, exit_code;
+#endif

=C2=A0 =C2=A0 =C2=A0/* Skip wait if qtest_probe_child already reaped.=C2=A0= */
=C2=A0 =C2=A0 =C2=A0if (pid !=3D -1) {
+#ifndef _WIN32
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0kill(pid, SIGTERM);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TFR(pid =3D waitpid(s->qemu_pid, &= s->wstatus, 0));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(pid =3D=3D s->qemu_pid);
+#else
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 TerminateProcess((HANDLE)pid, s->expected_s= tatus);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D WaitForSingleObject((HANDLE)pid, INFIN= ITE);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 assert(ret =3D=3D WAIT_OBJECT_0);
+#endif
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->qemu_pid =3D -1;
=C2=A0 =C2=A0 =C2=A0}

@@ -149,6 +184,7 @@ void qtest_kill_qemu(QTestState *s)
=C2=A0 =C2=A0 =C2=A0 * Check whether qemu exited with expected exit status;= anything else is
=C2=A0 =C2=A0 =C2=A0 * fishy and should be logged with as much detail as po= ssible.
=C2=A0 =C2=A0 =C2=A0 */
+#ifndef _WIN32
=C2=A0 =C2=A0 =C2=A0wstatus =3D s->wstatus;
=C2=A0 =C2=A0 =C2=A0if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) = !=3D s->expected_status) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fprintf(stderr, "%s:%d: kill_qemu() = tried to terminate QEMU "
@@ -165,6 +201,16 @@ void qtest_kill_qemu(QTestState *s)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0__FILE__, __L= INE__, sig, signame, dump);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0abort();
=C2=A0 =C2=A0 =C2=A0}
+#else
+=C2=A0 =C2=A0 GetExitCodeProcess((HANDLE)pid, &exit_code);
+=C2=A0 =C2=A0 CloseHandle((HANDLE)pid);
+=C2=A0 =C2=A0 if (exit_code !=3D s->expected_status) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 fprintf(stderr, "%s:%d: kill_qemu() tried= to terminate QEMU "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "process but = encountered exit status %ld (expected %d)\n",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 __FILE__, __LINE__= , exit_code, s->expected_status);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 abort();
+=C2=A0 =C2=A0 }
+#endif
=C2=A0}

=C2=A0static void kill_qemu_hook_func(void *s)
@@ -243,6 +289,38 @@ static const char *qtest_qemu_binary(void)
=C2=A0 =C2=A0 =C2=A0return qemu_bin;
=C2=A0}

+#ifdef _WIN32
+static pid_t qtest_create_process(char *cmd)
+{
+=C2=A0 =C2=A0 STARTUPINFO si;
+=C2=A0 =C2=A0 PROCESS_INFORMATION pi;
+=C2=A0 =C2=A0 BOOL ret;
+
+=C2=A0 =C2=A0 ZeroMemory(&si, sizeof(si));
+=C2=A0 =C2=A0 si.cb =3D sizeof(si);
+=C2=A0 =C2=A0 ZeroMemory(&pi, sizeof(pi));
+
+=C2=A0 =C2=A0 ret =3D CreateProcess(NULL,=C2=A0 =C2=A0/* module name */ +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 cmd,=C2=A0 =C2=A0 /* command line */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 NULL,=C2=A0 =C2=A0/* process handle not inheritable */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 NULL,=C2=A0 =C2=A0/* thread handle not inheritable */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 FALSE,=C2=A0 /* set handle inheritance to FALSE */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 0,=C2=A0 =C2=A0 =C2=A0 /* No creation flags */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 NULL,=C2=A0 =C2=A0/* use parent's environment block */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 NULL,=C2=A0 =C2=A0/* use parent's starting directory */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 &si,=C2=A0 =C2=A0 /* pointer to STARTUPINFO structure */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 &pi=C2=A0 =C2=A0 =C2=A0/* pointer to PROCESS_INFORMATION str= ucture */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 );
+=C2=A0 =C2=A0 if (ret =3D=3D 0) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 fprintf(stderr, "%s:%d: unable to create = a new process (%s)\n",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 __FILE__, __LINE__= , strerror(GetLastError()));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 abort();
+=C2=A0 =C2=A0 }
+
+=C2=A0 =C2=A0 return (pid_t)pi.hProcess;
+}
+#endif /* _WIN32 */
+
=C2=A0QTestState *qtest_init_without_qmp_handshake(const char *extra_args)<= br> =C2=A0{
=C2=A0 =C2=A0 =C2=A0QTestState *s;
@@ -270,6 +348,7 @@ QTestState *qtest_init_without_qmp_handshake(const char= *extra_args)
=C2=A0 =C2=A0 =C2=A0unlink(socket_path);
=C2=A0 =C2=A0 =C2=A0unlink(qmp_socket_path);

+=C2=A0 =C2=A0 socket_init();
=C2=A0 =C2=A0 =C2=A0sock =3D init_socket(socket_path);
=C2=A0 =C2=A0 =C2=A0qmpsock =3D init_socket(qmp_socket_path);

@@ -278,7 +357,7 @@ QTestState *qtest_init_without_qmp_handshake(const char= *extra_args)

=C2=A0 =C2=A0 =C2=A0qtest_add_abrt_handler(kill_qemu_hook_func, s);

-=C2=A0 =C2=A0 command =3D g_strdup_printf("exec %s %s"
+=C2=A0 =C2=A0 command =3D g_strdup_printf(CMD_EXEC "%s %s"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"-qtest unix:%s "
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"-qtest-log %s "
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"-chardev socket,path=3D%s,id=3D= char0 "
@@ -287,7 +366,7 @@ QTestState *qtest_init_without_qmp_handshake(const char= *extra_args)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"%s"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0" -accel qtest",
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_binary, tracearg, socket_path, -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 getenv("QTEST_LOG") ? "/dev/= fd/2" : "/dev/null",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 getenv("QTEST_LOG") ? DEV_STDERR = : DEV_NULL,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qmp_socket_path,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0extra_args ?: "");

@@ -296,6 +375,7 @@ QTestState *qtest_init_without_qmp_handshake(const char= *extra_args)
=C2=A0 =C2=A0 =C2=A0s->pending_events =3D NULL;
=C2=A0 =C2=A0 =C2=A0s->wstatus =3D 0;
=C2=A0 =C2=A0 =C2=A0s->expected_status =3D 0;
+#ifndef _WIN32
=C2=A0 =C2=A0 =C2=A0s->qemu_pid =3D fork();
=C2=A0 =C2=A0 =C2=A0if (s->qemu_pid =3D=3D 0) {
=C2=A0#ifdef __linux__
@@ -318,6 +398,9 @@ QTestState *qtest_init_without_qmp_handshake(const char= *extra_args)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0execlp("/bin/sh", "sh"= ;, "-c", command, NULL);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0exit(1);
=C2=A0 =C2=A0 =C2=A0}
+#else
+=C2=A0 =C2=A0 s->qemu_pid =3D qtest_create_process(command);
+#endif /* _WIN32 */

=C2=A0 =C2=A0 =C2=A0g_free(command);
=C2=A0 =C2=A0 =C2=A0s->fd =3D socket_accept(sock);
@@ -336,9 +419,19 @@ QTestState *qtest_init_without_qmp_handshake(const cha= r *extra_args)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->irq_level[i] =3D false;
=C2=A0 =C2=A0 =C2=A0}

+=C2=A0 =C2=A0 /*
+=C2=A0 =C2=A0 =C2=A0* Stopping QEMU for debugging is not supported on Wind= ows.
+=C2=A0 =C2=A0 =C2=A0*
+=C2=A0 =C2=A0 =C2=A0* Using DebugActiveProcess() API can suspend the QEMU = process,
+=C2=A0 =C2=A0 =C2=A0* but gdb cannot attach to the process. Using the undo= cumented
+=C2=A0 =C2=A0 =C2=A0* NtSuspendProcess() can suspend the QEMU process and = gdb can
+=C2=A0 =C2=A0 =C2=A0* attach to the process, but gdb cannot resume it.
+=C2=A0 =C2=A0 =C2=A0*/
+#ifndef _WIN32
=C2=A0 =C2=A0 =C2=A0if (getenv("QTEST_STOP")) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0kill(s->qemu_pid, SIGSTOP);
=C2=A0 =C2=A0 =C2=A0}
+#endif

=C2=A0 =C2=A0 =C2=A0/* ask endianness of the target */

@@ -392,6 +485,7 @@ QTestState *qtest_init_with_serial(const char *extra_ar= gs, int *sock_fd)
=C2=A0 =C2=A0 =C2=A0g_assert_true(sock_dir !=3D NULL);
=C2=A0 =C2=A0 =C2=A0sock_path =3D g_strdup_printf("%s/sock", sock= _dir);

+=C2=A0 =C2=A0 socket_init();
=C2=A0 =C2=A0 =C2=A0sock_fd_init =3D init_socket(sock_path);

=C2=A0 =C2=A0 =C2=A0qts =3D qtest_initf("-chardev socket,id=3Ds0,path= =3D%s -serial chardev:s0 %s",
--
2.34.1




--
Marc-Andr=C3=A9 Lureau
--00000000000050feac05e94981d5--