All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bin Meng <bmeng.cn@gmail.com>
To: qemu-devel@nongnu.org, Thomas Huth <thuth@redhat.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Bin Meng" <bin.meng@windriver.com>,
	"Xuzhou Cheng" <xuzhou.cheng@windriver.com>,
	"Laurent Vivier" <lvivier@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>
Subject: [PATCH v4 36/54] tests/qtest: Support libqtest to build and run on Windows
Date: Tue, 27 Sep 2022 19:06:14 +0800	[thread overview]
Message-ID: <20220927110632.1973965-37-bmeng.cn@gmail.com> (raw)
In-Reply-To: <20220927110632.1973965-1-bmeng.cn@gmail.com>

From: Bin Meng <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>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---

(no changes since v2)

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 f0ac467903..12b1e85b51 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__ */
@@ -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 = s->qemu_pid;
 
     if (pid != -1) {
+#ifndef _WIN32
         pid = waitpid(pid, &s->wstatus, WNOHANG);
         if (pid == 0) {
             return true;
         }
+#else
+        DWORD exit_code;
+        GetExitCodeProcess((HANDLE)pid, &exit_code);
+        if (exit_code == STILL_ACTIVE) {
+            return true;
+        }
+        CloseHandle((HANDLE)pid);
+#endif
         s->qemu_pid = -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 = s->qemu_pid;
+#ifndef _WIN32
     int wstatus;
+#else
+    DWORD ret, exit_code;
+#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);
+#endif
         s->qemu_pid = -1;
     }
 
@@ -149,6 +184,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 "
@@ -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 != 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 = 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;
@@ -270,6 +348,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);
 
@@ -278,7 +357,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 "
@@ -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_NULL,
                               qmp_socket_path,
                               extra_args ?: "");
 
@@ -296,6 +375,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__
@@ -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 = qtest_create_process(command);
+#endif /* _WIN32 */
 
     g_free(command);
     s->fd = socket_accept(sock);
@@ -336,9 +419,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 */
 
@@ -392,6 +485,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.34.1



  parent reply	other threads:[~2022-09-27 12:25 UTC|newest]

Thread overview: 86+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-27 11:05 [PATCH v4 00/54] tests/qtest: Enable running qtest on Windows Bin Meng
2022-09-27 11:05 ` [PATCH v4 01/54] tests/qtest: i440fx-test: Rewrite create_blob_file() to be portable Bin Meng
2022-09-27 11:05 ` [PATCH v4 02/54] semihosting/arm-compat-semi: Avoid using hardcoded /tmp Bin Meng
2022-10-01  3:41   ` Bin Meng
2022-09-27 11:05 ` [PATCH v4 03/54] tcg: " Bin Meng
2022-10-01  3:42   ` Bin Meng
2022-09-27 11:05 ` [PATCH v4 04/54] util/qemu-sockets: Use g_get_tmp_dir() to get the directory for temporary files Bin Meng
2022-10-01  3:44   ` Bin Meng
2022-10-03 10:28     ` Daniel P. Berrangé
2022-09-27 11:05 ` [PATCH v4 05/54] tests/qtest: ahci-test: Avoid using hardcoded /tmp Bin Meng
2022-09-27 11:05 ` [PATCH v4 06/54] tests/qtest: aspeed_smc-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 07/54] tests/qtest: boot-serial-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 08/54] tests/qtest: cxl-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 09/54] tests/qtest: fdc-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 10/54] tests/qtest: generic_fuzz: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 11/54] tests/qtest: virtio_blk_fuzz: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 12/54] tests/qtest: hd-geo-test: " Bin Meng
2022-09-27 12:21   ` Thomas Huth
2022-09-27 11:05 ` [PATCH v4 13/54] tests/qtest: ide-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 14/54] tests/qtest: migration-test: " Bin Meng
2022-09-27 14:26   ` Marc-André Lureau
2022-09-27 11:05 ` [PATCH v4 15/54] tests/qtest: pflash-cfi02-test: " Bin Meng
2022-09-27 14:27   ` Marc-André Lureau
2022-09-27 11:05 ` [PATCH v4 16/54] tests/qtest: qmp-test: " Bin Meng
2022-09-27 14:27   ` Marc-André Lureau
2022-09-27 11:05 ` [PATCH v4 17/54] tests/qtest: vhost-user-blk-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 18/54] tests/qtest: vhost-user-test: " Bin Meng
2022-09-27 14:28   ` Marc-André Lureau
2022-09-27 11:05 ` [PATCH v4 19/54] tests/qtest: virtio-blk-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 20/54] tests/qtest: virtio-scsi-test: " Bin Meng
2022-09-27 11:05 ` [PATCH v4 21/54] tests/qtest: libqtest: " Bin Meng
2022-09-27 11:06 ` [PATCH v4 22/54] tests/unit: test-image-locking: " Bin Meng
2022-09-27 11:06 ` [PATCH v4 23/54] tests/unit: test-qga: " Bin Meng
2022-09-27 11:06 ` [PATCH v4 24/54] tests: vhost-user-bridge: " Bin Meng
2022-09-27 11:06 ` [PATCH v4 25/54] block/vvfat: Unify the mkdir() call Bin Meng
2022-10-01  3:46   ` Bin Meng
2022-09-27 11:06 ` [PATCH v4 26/54] fsdev/virtfs-proxy-helper: Use g_mkdir() Bin Meng
2022-10-01  3:48   ` Bin Meng
2022-10-01 12:12     ` Christian Schoenebeck
2022-09-27 11:06 ` [PATCH v4 27/54] hw/usb: dev-mtp: " Bin Meng
2022-10-01  3:49   ` Bin Meng
2022-09-27 11:06 ` [PATCH v4 28/54] tests/qtest: Skip running virtio-net-test cases that require socketpair() for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 29/54] tests/qtest: Build test-filter-{mirror, redirector} cases for posix only Bin Meng
2022-09-27 11:06 ` [PATCH v4 30/54] tests/qtest: qmp-test: Skip running test_qmp_oob for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 31/54] accel/qtest: Implement a portable qtest accelerator Bin Meng
2022-09-28  9:00   ` Thomas Huth
2022-09-27 11:06 ` [PATCH v4 32/54] tests/qtest: libqtest: Adapt global_qtest declaration for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 33/54] tests/qtest: Use send/recv for socket communication Bin Meng
2022-09-27 11:06 ` [PATCH v4 34/54] tests/qtest: libqtest: Exclude the *_fds APIs for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 35/54] tests/qtest: libqtest: Install signal handler via signal() Bin Meng
2022-09-28  9:42   ` Thomas Huth
2022-09-28  9:57     ` Bin Meng
2022-09-28 10:03       ` Thomas Huth
2022-09-27 11:06 ` Bin Meng [this message]
2022-09-27 11:06 ` [PATCH v4 37/54] tests/qtest: {ahci, ide}-test: Use relative path for temporary files for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 38/54] tests/qtest: bios-tables-test: Adapt the case " Bin Meng
2022-09-27 11:06 ` [PATCH v4 39/54] tests/qtest: boot-serial-test: Close the serial file before starting QEMU Bin Meng
2022-09-27 14:29   ` Marc-André Lureau
2022-09-27 11:06 ` [PATCH v4 40/54] tests/qtest: ide-test: Open file in binary mode Bin Meng
2022-09-27 11:06 ` [PATCH v4 41/54] tests/qtest: microbit-test: Fix socket access for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 42/54] tests/qtest: migration-test: Disable IO redirection " Bin Meng
2022-09-27 11:06 ` [PATCH v4 43/54] tests/qtest: migration-test: Make sure QEMU process "to" exited after migration is canceled Bin Meng
2022-09-27 13:15   ` Marc-André Lureau
2022-09-27 13:21     ` Bin Meng
2022-09-27 14:23       ` Marc-André Lureau
2022-09-27 11:06 ` [PATCH v4 44/54] tests/qtest: virtio-net-failover: Disable migration tests for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 45/54] tests/qtest: libqtest: Replace the call to close a socket with closesocket() Bin Meng
2022-09-27 11:06 ` [PATCH v4 46/54] tests/qtest: libqtest: Correct the timeout unit of blocking receive calls for win32 Bin Meng
2022-09-27 11:06 ` [PATCH v4 47/54] io/channel-watch: Drop a superfluous '#ifdef WIN32' Bin Meng
2022-09-27 11:06 ` [PATCH v4 48/54] io/channel-watch: Drop the unnecessary cast Bin Meng
2022-09-27 11:06 ` [PATCH v4 49/54] io/channel-watch: Fix socket watch on Windows Bin Meng
2022-09-27 11:06 ` [PATCH v4 50/54] tests/qtest: migration-test: Skip running some TLS cases for win32 Bin Meng
2022-09-27 14:32   ` Marc-André Lureau
2022-09-27 14:38     ` Bin Meng
2022-09-27 14:47       ` Marc-André Lureau
2022-09-27 11:06 ` [PATCH v4 51/54] .gitlab-ci.d/windows.yml: Increase the timeout to 90 minutes Bin Meng
2022-09-27 11:06 ` [PATCH v4 52/54] .gitlab-ci.d/windows.yml: Display meson test logs Bin Meng
2022-09-27 11:06 ` [PATCH v4 53/54] tests/qtest: Enable qtest build on Windows Bin Meng
2022-09-27 13:34   ` Thomas Huth
2022-09-27 11:06 ` [PATCH v4 54/54] docs/devel: testing: Document writing portable test cases Bin Meng
2022-09-27 13:36   ` Thomas Huth
2022-09-28 10:31 ` [PATCH v4 00/54] tests/qtest: Enable running qtest on Windows Thomas Huth
2022-09-28 15:24   ` Thomas Huth
2022-09-28 15:30     ` Daniel P. Berrangé
2022-10-03  9:25 ` Marc-André Lureau
2022-10-03 10:08   ` Bin Meng

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=20220927110632.1973965-37-bmeng.cn@gmail.com \
    --to=bmeng.cn@gmail.com \
    --cc=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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.