libqtest: ensure waitpid() is only called once
If a test aborts after qtest_wait_qemu() is called, the SIGABRT hooks are still in place and waitpid() is called again. The second time it is called, the process does not exist anymore and the system call fails. Move the s->qemu_pid = -1 assignment to qtest_wait_qemu() to make it idempotent, and anyway remove the SIGABRT hook as well to avoid that qtest_check_status() is called twice. Because of the extra call, qtest_remove_abrt_handler() now has to be made idempotent as well. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
786c5256d3
commit
12008ff748
@ -158,6 +158,7 @@ bool qtest_probe_child(QTestState *s)
|
||||
CloseHandle((HANDLE)pid);
|
||||
#endif
|
||||
s->qemu_pid = -1;
|
||||
qtest_remove_abrt_handler(s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -169,6 +170,8 @@ void qtest_set_expected_status(QTestState *s, int status)
|
||||
|
||||
static void qtest_check_status(QTestState *s)
|
||||
{
|
||||
assert(s->qemu_pid == -1);
|
||||
|
||||
/*
|
||||
* Check whether qemu exited with expected exit status; anything else is
|
||||
* fishy and should be logged with as much detail as possible.
|
||||
@ -202,36 +205,40 @@ static void qtest_check_status(QTestState *s)
|
||||
|
||||
void qtest_wait_qemu(QTestState *s)
|
||||
{
|
||||
if (s->qemu_pid != -1) {
|
||||
#ifndef _WIN32
|
||||
pid_t pid;
|
||||
uint64_t end;
|
||||
pid_t pid;
|
||||
uint64_t end;
|
||||
|
||||
/* poll for a while until sending SIGKILL */
|
||||
end = g_get_monotonic_time() + WAITPID_TIMEOUT * G_TIME_SPAN_SECOND;
|
||||
/* poll for a while until sending SIGKILL */
|
||||
end = g_get_monotonic_time() + WAITPID_TIMEOUT * G_TIME_SPAN_SECOND;
|
||||
|
||||
do {
|
||||
pid = waitpid(s->qemu_pid, &s->wstatus, WNOHANG);
|
||||
if (pid != 0) {
|
||||
break;
|
||||
do {
|
||||
pid = waitpid(s->qemu_pid, &s->wstatus, WNOHANG);
|
||||
if (pid != 0) {
|
||||
break;
|
||||
}
|
||||
g_usleep(100 * 1000);
|
||||
} while (g_get_monotonic_time() < end);
|
||||
|
||||
if (pid == 0) {
|
||||
kill(s->qemu_pid, SIGKILL);
|
||||
pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0));
|
||||
}
|
||||
g_usleep(100 * 1000);
|
||||
} while (g_get_monotonic_time() < end);
|
||||
|
||||
if (pid == 0) {
|
||||
kill(s->qemu_pid, SIGKILL);
|
||||
pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0));
|
||||
}
|
||||
|
||||
assert(pid == s->qemu_pid);
|
||||
assert(pid == s->qemu_pid);
|
||||
#else
|
||||
DWORD ret;
|
||||
DWORD ret;
|
||||
|
||||
ret = WaitForSingleObject((HANDLE)s->qemu_pid, INFINITE);
|
||||
assert(ret == WAIT_OBJECT_0);
|
||||
GetExitCodeProcess((HANDLE)s->qemu_pid, &s->exit_code);
|
||||
CloseHandle((HANDLE)s->qemu_pid);
|
||||
ret = WaitForSingleObject((HANDLE)s->qemu_pid, INFINITE);
|
||||
assert(ret == WAIT_OBJECT_0);
|
||||
GetExitCodeProcess((HANDLE)s->qemu_pid, &s->exit_code);
|
||||
CloseHandle((HANDLE)s->qemu_pid);
|
||||
#endif
|
||||
|
||||
s->qemu_pid = -1;
|
||||
qtest_remove_abrt_handler(s);
|
||||
}
|
||||
qtest_check_status(s);
|
||||
}
|
||||
|
||||
@ -245,7 +252,6 @@ void qtest_kill_qemu(QTestState *s)
|
||||
TerminateProcess((HANDLE)s->qemu_pid, s->expected_status);
|
||||
#endif
|
||||
qtest_wait_qemu(s);
|
||||
s->qemu_pid = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -307,6 +313,11 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data)
|
||||
void qtest_remove_abrt_handler(void *data)
|
||||
{
|
||||
GHook *hook = g_hook_find_data(&abrt_hooks, TRUE, data);
|
||||
|
||||
if (!hook) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_hook_destroy_link(&abrt_hooks, hook);
|
||||
|
||||
/* Uninstall SIGABRT handler on last instance */
|
||||
|
Loading…
Reference in New Issue
Block a user