From: Bin Meng <bin.meng@windriver.com>
To: qemu-devel@nongnu.org
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>,
"Xuzhou Cheng" <xuzhou.cheng@windriver.com>,
"Laurent Vivier" <lvivier@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Thomas Huth" <thuth@redhat.com>
Subject: [PATCH v6 03/11] tests/qtest: Support libqtest to build and run on Windows
Date: Fri, 28 Oct 2022 12:57:28 +0800 [thread overview]
Message-ID: <20221028045736.679903-4-bin.meng@windriver.com> (raw)
In-Reply-To: <20221028045736.679903-1-bin.meng@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>
---
Changes in v6:
- save the "exit_code" in struct QTestState
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 | 96 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 94 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index b01846fd98..d12a604d78 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -16,9 +16,11 @@
#include "qemu/osdep.h"
+#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
+#endif /* _WIN32 */
#ifdef __linux__
#include <sys/prctl.h>
#endif /* __linux__ */
@@ -36,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 *);
@@ -58,6 +70,9 @@ struct QTestState
int qmp_fd;
pid_t qemu_pid; /* our child QEMU process */
int wstatus;
+#ifdef _WIN32
+ DWORD exit_code;
+#endif
int expected_status;
bool big_endian;
bool irq_level[MAX_IRQ];
@@ -119,10 +134,18 @@ bool qtest_probe_child(QTestState *s)
pid_t pid = s->qemu_pid;
if (pid != -1) {
+#ifndef _WIN32
pid = waitpid(pid, &s->wstatus, WNOHANG);
if (pid == 0) {
return true;
}
+#else
+ GetExitCodeProcess((HANDLE)pid, &s->exit_code);
+ if (s->exit_code == STILL_ACTIVE) {
+ return true;
+ }
+ CloseHandle((HANDLE)pid);
+#endif
s->qemu_pid = -1;
}
return false;
@@ -136,13 +159,25 @@ void qtest_set_expected_status(QTestState *s, int status)
void qtest_kill_qemu(QTestState *s)
{
pid_t pid = s->qemu_pid;
+#ifndef _WIN32
int wstatus;
+#else
+ DWORD ret;
+#endif
/* Skip wait if qtest_probe_child already reaped. */
if (pid != -1) {
+#ifndef _WIN32
kill(pid, SIGTERM);
TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0));
assert(pid == s->qemu_pid);
+#else
+ TerminateProcess((HANDLE)pid, s->expected_status);
+ ret = WaitForSingleObject((HANDLE)pid, INFINITE);
+ assert(ret == WAIT_OBJECT_0);
+ GetExitCodeProcess((HANDLE)pid, &s->exit_code);
+ CloseHandle((HANDLE)pid);
+#endif
s->qemu_pid = -1;
}
@@ -150,6 +185,7 @@ void qtest_kill_qemu(QTestState *s)
* Check whether qemu exited with expected exit status; anything else is
* fishy and should be logged with as much detail as possible.
*/
+#ifndef _WIN32
wstatus = s->wstatus;
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != s->expected_status) {
fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
@@ -166,6 +202,14 @@ void qtest_kill_qemu(QTestState *s)
__FILE__, __LINE__, sig, signame, dump);
abort();
}
+#else
+ if (s->exit_code != s->expected_status) {
+ fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
+ "process but encountered exit status %ld (expected %d)\n",
+ __FILE__, __LINE__, s->exit_code, s->expected_status);
+ abort();
+ }
+#endif
}
static void kill_qemu_hook_func(void *s)
@@ -244,6 +288,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 = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ ret = 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 == 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;
@@ -271,6 +347,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
unlink(socket_path);
unlink(qmp_socket_path);
+ socket_init();
sock = init_socket(socket_path);
qmpsock = init_socket(qmp_socket_path);
@@ -279,7 +356,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
qtest_add_abrt_handler(kill_qemu_hook_func, s);
- command = g_strdup_printf("exec %s %s"
+ command = g_strdup_printf(CMD_EXEC "%s %s"
"-qtest unix:%s "
"-qtest-log %s "
"-chardev socket,path=%s,id=char0 "
@@ -288,7 +365,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_NULL,
qmp_socket_path,
extra_args ?: "");
@@ -297,6 +374,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
s->pending_events = NULL;
s->wstatus = 0;
s->expected_status = 0;
+#ifndef _WIN32
s->qemu_pid = fork();
if (s->qemu_pid == 0) {
#ifdef __linux__
@@ -319,6 +397,9 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
execlp("/bin/sh", "sh", "-c", command, NULL);
exit(1);
}
+#else
+ s->qemu_pid = qtest_create_process(command);
+#endif /* _WIN32 */
g_free(command);
s->fd = socket_accept(sock);
@@ -337,9 +418,19 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
s->irq_level[i] = 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 */
@@ -393,6 +484,7 @@ QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd)
g_assert_true(sock_dir != NULL);
sock_path = g_strdup_printf("%s/sock", sock_dir);
+ socket_init();
sock_fd_init = init_socket(sock_path);
qts = qtest_initf("-chardev socket,id=s0,path=%s -serial chardev:s0 %s",
--
2.25.1
next prev parent reply other threads:[~2022-10-28 5:01 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-28 4:57 [PATCH v6 00/11] tests/qtest: Enable running qtest on Windows Bin Meng
2022-10-28 4:57 ` [PATCH v6 01/11] accel/qtest: Support qtest accelerator for Windows Bin Meng
2022-10-28 4:57 ` [PATCH v6 02/11] tests/qtest: Use send/recv for socket communication Bin Meng
2022-10-28 4:57 ` Bin Meng [this message]
2022-10-28 4:57 ` [PATCH v6 04/11] tests/qtest: device-plug-test: Reverse the usage of double/single quotes Bin Meng
2022-10-28 7:49 ` Thomas Huth
2022-10-28 4:57 ` [PATCH v6 05/11] tests/qtest: Use EXIT_FAILURE instead of magic number Bin Meng
2022-10-28 8:02 ` Thomas Huth
2022-10-28 12:31 ` Juan Quintela
2022-10-28 4:57 ` [PATCH v6 06/11] tests/qtest: libqtest: Introduce qtest_wait_qemu() Bin Meng
2022-10-28 8:05 ` Thomas Huth
2022-10-28 4:57 ` [PATCH v6 07/11] tests/qtest: migration-test: Make sure QEMU process "to" exited after migration is canceled Bin Meng
2022-10-28 13:34 ` Juan Quintela
2022-10-28 4:57 ` [PATCH v6 08/11] tests/qtest: libqos: Do not build virtio-9p unconditionally Bin Meng
2022-10-28 7:56 ` Thomas Huth
2022-10-28 12:59 ` Christian Schoenebeck
2022-10-28 13:09 ` Thomas Huth
2022-10-28 13:34 ` Christian Schoenebeck
2022-10-28 4:57 ` [PATCH v6 09/11] tests/qtest: libqtest: Correct the timeout unit of blocking receive calls for win32 Bin Meng
2022-10-28 4:57 ` [PATCH v6 10/11] .gitlab-ci.d/windows.yml: Increase the timeout to 90 minutes Bin Meng
2022-10-28 4:57 ` [PATCH v6 11/11] tests/qtest: Enable qtest build on Windows Bin Meng
2022-11-23 14:13 ` Marc-André Lureau
2022-11-23 14:19 ` Thomas Huth
2022-11-24 11:17 ` Marc-André Lureau
2022-11-24 11:49 ` Thomas Huth
2022-11-24 12:00 ` Marc-André Lureau
2022-11-25 10:04 ` Bin Meng
2022-10-28 8:06 ` [PATCH v6 00/11] tests/qtest: Enable running qtest " Marc-André Lureau
2022-10-28 9:20 ` Bin Meng
2022-10-28 9:40 ` Marc-André Lureau
2022-10-28 9:43 ` Bin Meng
2022-10-28 11:49 ` Thomas Huth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221028045736.679903-4-bin.meng@windriver.com \
--to=bin.meng@windriver.com \
--cc=lvivier@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=thuth@redhat.com \
--cc=xuzhou.cheng@windriver.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).