From 9fb7bb06986741b7fd8427fac9f22177ca38dcff Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 23 Feb 2021 14:46:43 +0000 Subject: libqtest: add qtest_socket_server() Add an API that returns a new UNIX domain socket in the listen state. The code for this was already there but only used internally in init_socket(). This new API will be used by vhost-user-blk-test. Signed-off-by: Stefan Hajnoczi Reviewed-by: Thomas Huth Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210223144653.811468-3-stefanha@redhat.com> Signed-off-by: Kevin Wolf --- tests/qtest/libqos/libqtest.h | 8 ++++++++ tests/qtest/libqtest.c | 40 +++++++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 17 deletions(-) (limited to 'tests/qtest') diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h index 724f65aa94..e5f1ec590c 100644 --- a/tests/qtest/libqos/libqtest.h +++ b/tests/qtest/libqos/libqtest.h @@ -132,6 +132,14 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...) void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3); +/** + * qtest_socket_server: + * @socket_path: the UNIX domain socket path + * + * Create and return a listen socket file descriptor, or abort on failure. + */ +int qtest_socket_server(const char *socket_path); + /** * qtest_vqmp_fds: * @s: #QTestState instance to operate on. diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index fd043b0570..b19d2ebda0 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -81,24 +81,8 @@ static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv); static int init_socket(const char *socket_path) { - struct sockaddr_un addr; - int sock; - int ret; - - sock = socket(PF_UNIX, SOCK_STREAM, 0); - g_assert_cmpint(sock, !=, -1); - - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); + int sock = qtest_socket_server(socket_path); qemu_set_cloexec(sock); - - do { - ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); - } while (ret == -1 && errno == EINTR); - g_assert_cmpint(ret, !=, -1); - ret = listen(sock, 1); - g_assert_cmpint(ret, !=, -1); - return sock; } @@ -638,6 +622,28 @@ QDict *qtest_qmp_receive_dict(QTestState *s) return qmp_fd_receive(s->qmp_fd); } +int qtest_socket_server(const char *socket_path) +{ + struct sockaddr_un addr; + int sock; + int ret; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + g_assert_cmpint(sock, !=, -1); + + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); + + do { + ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + } while (ret == -1 && errno == EINTR); + g_assert_cmpint(ret, !=, -1); + ret = listen(sock, 1); + g_assert_cmpint(ret, !=, -1); + + return sock; +} + /** * Allow users to send a message without waiting for the reply, * in the case that they choose to discard all replies up until -- cgit v1.2.3-55-g7522 From 7a23c523762371fd26a7a9ecfa8f16b64618a1ad Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 23 Feb 2021 14:46:44 +0000 Subject: libqtest: add qtest_kill_qemu() Tests that manage multiple processes may wish to kill QEMU before destroying the QTestState. Expose a function to do that. The vhost-user-blk-test testcase will need this. Signed-off-by: Stefan Hajnoczi Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210223144653.811468-4-stefanha@redhat.com> Signed-off-by: Kevin Wolf --- tests/qtest/libqos/libqtest.h | 11 +++++++++++ tests/qtest/libqtest.c | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'tests/qtest') diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h index e5f1ec590c..51287b9276 100644 --- a/tests/qtest/libqos/libqtest.h +++ b/tests/qtest/libqos/libqtest.h @@ -74,6 +74,17 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args); */ QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd); +/** + * qtest_kill_qemu: + * @s: #QTestState instance to operate on. + * + * Kill the QEMU process and wait for it to terminate. It is safe to call this + * function multiple times. Normally qtest_quit() is used instead because it + * also frees QTestState. Use qtest_kill_qemu() when you just want to kill QEMU + * and qtest_quit() will be called later. + */ +void qtest_kill_qemu(QTestState *s); + /** * qtest_quit: * @s: #QTestState instance to operate on. diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index b19d2ebda0..2a98de2907 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -133,7 +133,7 @@ void qtest_set_expected_status(QTestState *s, int status) s->expected_status = status; } -static void kill_qemu(QTestState *s) +void qtest_kill_qemu(QTestState *s) { pid_t pid = s->qemu_pid; int wstatus; @@ -143,6 +143,7 @@ static void kill_qemu(QTestState *s) kill(pid, SIGTERM); TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0)); assert(pid == s->qemu_pid); + s->qemu_pid = -1; } /* @@ -169,7 +170,7 @@ static void kill_qemu(QTestState *s) static void kill_qemu_hook_func(void *s) { - kill_qemu(s); + qtest_kill_qemu(s); } static void sigabrt_handler(int signo) @@ -373,7 +374,7 @@ void qtest_quit(QTestState *s) /* Uninstall SIGABRT handler on last instance */ cleanup_sigabrt_handler(); - kill_qemu(s); + qtest_kill_qemu(s); close(s->fd); close(s->qmp_fd); g_string_free(s->rx, true); -- cgit v1.2.3-55-g7522 From e1fa7f5591c219a94f039754f6fbe58e757e7af6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 23 Feb 2021 14:46:45 +0000 Subject: libqtest: add qtest_remove_abrt_handler() Add a function to remove previously-added abrt handler functions. Now that a symmetric pair of add/remove functions exists we can also balance the SIGABRT handler installation. The signal handler was installed each time qtest_add_abrt_handler() was called. Now it is installed when the abrt handler list becomes non-empty and removed again when the list becomes empty. The qtest_remove_abrt_handler() function will be used by vhost-user-blk-test. Signed-off-by: Stefan Hajnoczi Reviewed-by: Wainer dos Santos Moschetta Message-Id: <20210223144653.811468-5-stefanha@redhat.com> Signed-off-by: Kevin Wolf --- tests/qtest/libqos/libqtest.h | 18 ++++++++++++++++++ tests/qtest/libqtest.c | 35 +++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 6 deletions(-) (limited to 'tests/qtest') diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h index 51287b9276..a68dcd79d4 100644 --- a/tests/qtest/libqos/libqtest.h +++ b/tests/qtest/libqos/libqtest.h @@ -649,8 +649,26 @@ void qtest_add_data_func_full(const char *str, void *data, g_free(path); \ } while (0) +/** + * qtest_add_abrt_handler: + * @fn: Handler function + * @data: Argument that is passed to the handler + * + * Add a handler function that is invoked on SIGABRT. This can be used to + * terminate processes and perform other cleanup. The handler can be removed + * with qtest_remove_abrt_handler(). + */ void qtest_add_abrt_handler(GHookFunc fn, const void *data); +/** + * qtest_remove_abrt_handler: + * @data: Argument previously passed to qtest_add_abrt_handler() + * + * Remove an abrt handler that was previously added with + * qtest_add_abrt_handler(). + */ +void qtest_remove_abrt_handler(void *data); + /** * qtest_qmp_assert_success: * @qts: QTestState instance to operate on diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 2a98de2907..71e359efcd 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -196,15 +196,30 @@ static void cleanup_sigabrt_handler(void) sigaction(SIGABRT, &sigact_old, NULL); } +static bool hook_list_is_empty(GHookList *hook_list) +{ + GHook *hook = g_hook_first_valid(hook_list, TRUE); + + if (!hook) { + return false; + } + + g_hook_unref(hook_list, hook); + return true; +} + void qtest_add_abrt_handler(GHookFunc fn, const void *data) { GHook *hook; - /* Only install SIGABRT handler once */ if (!abrt_hooks.is_setup) { g_hook_list_init(&abrt_hooks, sizeof(GHook)); } - setup_sigabrt_handler(); + + /* Only install SIGABRT handler once */ + if (hook_list_is_empty(&abrt_hooks)) { + setup_sigabrt_handler(); + } hook = g_hook_alloc(&abrt_hooks); hook->func = fn; @@ -213,6 +228,17 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data) g_hook_prepend(&abrt_hooks, hook); } +void qtest_remove_abrt_handler(void *data) +{ + GHook *hook = g_hook_find_data(&abrt_hooks, TRUE, data); + g_hook_destroy_link(&abrt_hooks, hook); + + /* Uninstall SIGABRT handler on last instance */ + if (hook_list_is_empty(&abrt_hooks)) { + cleanup_sigabrt_handler(); + } +} + static const char *qtest_qemu_binary(void) { const char *qemu_bin; @@ -369,10 +395,7 @@ QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd) void qtest_quit(QTestState *s) { - g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s)); - - /* Uninstall SIGABRT handler on last instance */ - cleanup_sigabrt_handler(); + qtest_remove_abrt_handler(s); qtest_kill_qemu(s); close(s->fd); -- cgit v1.2.3-55-g7522