2011-09-13 10:30:52 +02:00
|
|
|
/*
|
|
|
|
* QEMU System Emulator
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2016-01-29 18:50:05 +01:00
|
|
|
#include "qemu/osdep.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 09:01:28 +01:00
|
|
|
#include "qapi/error.h"
|
2016-03-20 18:16:19 +01:00
|
|
|
#include "qemu/cutils.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/timer.h"
|
2014-03-13 15:17:29 +01:00
|
|
|
#include "sysemu/qtest.h"
|
2020-08-19 13:17:19 +02:00
|
|
|
#include "sysemu/cpu-timers.h"
|
2018-02-27 10:52:48 +01:00
|
|
|
#include "sysemu/replay.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/main-loop.h"
|
2012-12-17 18:19:44 +01:00
|
|
|
#include "block/aio.h"
|
2017-09-11 21:52:53 +02:00
|
|
|
#include "qemu/error-report.h"
|
2019-07-12 19:34:35 +02:00
|
|
|
#include "qemu/queue.h"
|
cfi: Initial support for cfi-icall in QEMU
LLVM/Clang, supports runtime checks for forward-edge Control-Flow
Integrity (CFI).
CFI on indirect function calls (cfi-icall) ensures that, in indirect
function calls, the function called is of the right signature for the
pointer type defined at compile time.
For this check to work, the code must always respect the function
signature when using function pointer, the function must be defined
at compile time, and be compiled with link-time optimization.
This rules out, for example, shared libraries that are dynamically loaded
(given that functions are not known at compile time), and code that is
dynamically generated at run-time.
This patch:
1) Introduces the CONFIG_CFI flag to support cfi in QEMU
2) Introduces a decorator to allow the definition of "sensitive"
functions, where a non-instrumented function may be called at runtime
through a pointer. The decorator will take care of disabling cfi-icall
checks on such functions, when cfi is enabled.
3) Marks functions currently in QEMU that exhibit such behavior,
in particular:
- The function in TCG that calls pre-compiled TBs
- The function in TCI that interprets instructions
- Functions in the plugin infrastructures that jump to callbacks
- Functions in util that directly call a signal handler
Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>
Acked-by: Alex Bennée <alex.bennee@linaro.org
Message-Id: <20201204230615.2392-3-dbuono@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2020-12-05 00:06:12 +01:00
|
|
|
#include "qemu/compiler.h"
|
2019-07-12 19:34:35 +02:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#endif
|
2011-09-13 10:30:52 +02:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
|
|
/* If we have signalfd, we mask out the signals we want to handle and then
|
|
|
|
* use signalfd to listen for them. We rely on whatever the current signal
|
|
|
|
* handler is to dispatch the signals when we receive them.
|
|
|
|
*/
|
cfi: Initial support for cfi-icall in QEMU
LLVM/Clang, supports runtime checks for forward-edge Control-Flow
Integrity (CFI).
CFI on indirect function calls (cfi-icall) ensures that, in indirect
function calls, the function called is of the right signature for the
pointer type defined at compile time.
For this check to work, the code must always respect the function
signature when using function pointer, the function must be defined
at compile time, and be compiled with link-time optimization.
This rules out, for example, shared libraries that are dynamically loaded
(given that functions are not known at compile time), and code that is
dynamically generated at run-time.
This patch:
1) Introduces the CONFIG_CFI flag to support cfi in QEMU
2) Introduces a decorator to allow the definition of "sensitive"
functions, where a non-instrumented function may be called at runtime
through a pointer. The decorator will take care of disabling cfi-icall
checks on such functions, when cfi is enabled.
3) Marks functions currently in QEMU that exhibit such behavior,
in particular:
- The function in TCG that calls pre-compiled TBs
- The function in TCI that interprets instructions
- Functions in the plugin infrastructures that jump to callbacks
- Functions in util that directly call a signal handler
Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>
Acked-by: Alex Bennée <alex.bennee@linaro.org
Message-Id: <20201204230615.2392-3-dbuono@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2020-12-05 00:06:12 +01:00
|
|
|
/*
|
|
|
|
* Disable CFI checks.
|
|
|
|
* We are going to call a signal hander directly. Such handler may or may not
|
|
|
|
* have been defined in our binary, so there's no guarantee that the pointer
|
|
|
|
* used to set the handler is a cfi-valid pointer. Since the handlers are
|
|
|
|
* stored in kernel memory, changing the handler to an attacker-defined
|
|
|
|
* function requires being able to call a sigaction() syscall,
|
|
|
|
* which is not as easy as overwriting a pointer in memory.
|
|
|
|
*/
|
|
|
|
QEMU_DISABLE_CFI
|
2011-09-13 10:30:52 +02:00
|
|
|
static void sigfd_handler(void *opaque)
|
|
|
|
{
|
|
|
|
int fd = (intptr_t)opaque;
|
|
|
|
struct qemu_signalfd_siginfo info;
|
|
|
|
struct sigaction action;
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
do {
|
|
|
|
len = read(fd, &info, sizeof(info));
|
|
|
|
} while (len == -1 && errno == EINTR);
|
|
|
|
|
|
|
|
if (len == -1 && errno == EAGAIN) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len != sizeof(info)) {
|
2019-10-18 15:07:16 +02:00
|
|
|
error_report("read from sigfd returned %zd: %s", len,
|
|
|
|
g_strerror(errno));
|
2011-09-13 10:30:52 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sigaction(info.ssi_signo, NULL, &action);
|
|
|
|
if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
|
2017-02-08 13:22:12 +01:00
|
|
|
sigaction_invoke(&action, &info);
|
2011-09-13 10:30:52 +02:00
|
|
|
} else if (action.sa_handler) {
|
|
|
|
action.sa_handler(info.ssi_signo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-13 15:08:45 +01:00
|
|
|
static int qemu_signal_init(Error **errp)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
|
|
|
int sigfd;
|
|
|
|
sigset_t set;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SIG_IPI must be blocked in the main thread and must not be caught
|
|
|
|
* by sigwait() in the signal thread. Otherwise, the cpu thread will
|
|
|
|
* not catch it reliably.
|
|
|
|
*/
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIG_IPI);
|
|
|
|
sigaddset(&set, SIGIO);
|
|
|
|
sigaddset(&set, SIGALRM);
|
|
|
|
sigaddset(&set, SIGBUS);
|
2014-10-27 15:13:02 +01:00
|
|
|
/* SIGINT cannot be handled via signalfd, so that ^C can be used
|
|
|
|
* to interrupt QEMU when it is being run under gdb. SIGHUP and
|
|
|
|
* SIGTERM are also handled asynchronously, even though it is not
|
|
|
|
* strictly necessary, because they use the same handler as SIGINT.
|
|
|
|
*/
|
2011-09-13 10:30:52 +02:00
|
|
|
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
|
|
|
|
2012-01-12 10:05:35 +01:00
|
|
|
sigdelset(&set, SIG_IPI);
|
2011-09-13 10:30:52 +02:00
|
|
|
sigfd = qemu_signalfd(&set);
|
|
|
|
if (sigfd == -1) {
|
2019-01-13 15:08:45 +01:00
|
|
|
error_setg_errno(errp, errno, "failed to create signalfd");
|
2011-09-13 10:30:52 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
fcntl_setfl(sigfd, O_NONBLOCK);
|
|
|
|
|
Change qemu_set_fd_handler2(..., NULL, ...) to qemu_set_fd_handler
Done with following Coccinelle semantic patch, plus manual cosmetic changes in
net/*.c.
@@
expression E1, E2, E3, E4;
@@
- qemu_set_fd_handler2(E1, NULL, E2, E3, E4);
+ qemu_set_fd_handler(E1, E2, E3, E4);
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-8-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-04 08:45:18 +02:00
|
|
|
qemu_set_fd_handler(sigfd, sigfd_handler, NULL, (void *)(intptr_t)sigfd);
|
2011-09-13 10:30:52 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* _WIN32 */
|
|
|
|
|
2019-01-13 15:08:45 +01:00
|
|
|
static int qemu_signal_init(Error **errp)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2010-05-24 17:27:14 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static AioContext *qemu_aio_context;
|
2015-07-24 13:42:55 +02:00
|
|
|
static QEMUBH *qemu_notify_bh;
|
|
|
|
|
|
|
|
static void notify_event_cb(void *opaque)
|
|
|
|
{
|
|
|
|
/* No need to do anything; this bottom half is only used to
|
|
|
|
* kick the kernel out of ppoll/poll/WaitForMultipleObjects.
|
|
|
|
*/
|
|
|
|
}
|
2011-09-13 10:30:52 +02:00
|
|
|
|
2013-03-07 13:41:44 +01:00
|
|
|
AioContext *qemu_get_aio_context(void)
|
|
|
|
{
|
|
|
|
return qemu_aio_context;
|
|
|
|
}
|
|
|
|
|
2011-09-13 10:30:52 +02:00
|
|
|
void qemu_notify_event(void)
|
|
|
|
{
|
2010-05-24 17:27:14 +02:00
|
|
|
if (!qemu_aio_context) {
|
2012-01-21 02:08:27 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-07-24 13:42:55 +02:00
|
|
|
qemu_bh_schedule(qemu_notify_bh);
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
|
|
|
|
2013-02-20 11:28:25 +01:00
|
|
|
static GArray *gpollfds;
|
|
|
|
|
2014-09-18 13:30:49 +02:00
|
|
|
int qemu_init_main_loop(Error **errp)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
|
|
|
int ret;
|
2012-09-24 15:07:08 +02:00
|
|
|
GSource *src;
|
2011-09-13 10:30:52 +02:00
|
|
|
|
2017-03-03 11:50:29 +01:00
|
|
|
init_clocks(qemu_timer_notify_cb);
|
2012-10-29 15:28:36 +01:00
|
|
|
|
2019-01-13 15:08:45 +01:00
|
|
|
ret = qemu_signal_init(errp);
|
2011-09-13 10:30:52 +02:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 18:06:02 +02:00
|
|
|
qemu_aio_context = aio_context_new(errp);
|
2014-09-18 13:30:49 +02:00
|
|
|
if (!qemu_aio_context) {
|
|
|
|
return -EMFILE;
|
|
|
|
}
|
2016-07-06 12:08:59 +02:00
|
|
|
qemu_notify_bh = qemu_bh_new(notify_event_cb, NULL);
|
2013-02-20 11:28:25 +01:00
|
|
|
gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
2012-09-24 15:07:08 +02:00
|
|
|
src = aio_get_g_source(qemu_aio_context);
|
2016-09-30 16:34:24 +02:00
|
|
|
g_source_set_name(src, "aio-context");
|
2012-09-24 15:07:08 +02:00
|
|
|
g_source_attach(src, NULL);
|
|
|
|
g_source_unref(src);
|
2015-09-07 05:28:58 +02:00
|
|
|
src = iohandler_get_g_source();
|
2016-09-30 16:34:24 +02:00
|
|
|
g_source_set_name(src, "io-handler");
|
2015-09-07 05:28:58 +02:00
|
|
|
g_source_attach(src, NULL);
|
|
|
|
g_source_unref(src);
|
2011-09-13 10:30:52 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int max_priority;
|
|
|
|
|
2012-03-20 10:49:21 +01:00
|
|
|
#ifndef _WIN32
|
2013-02-20 11:28:26 +01:00
|
|
|
static int glib_pollfds_idx;
|
|
|
|
static int glib_n_poll_fds;
|
|
|
|
|
2020-09-02 13:17:24 +02:00
|
|
|
void qemu_fd_register(int fd)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
static void glib_pollfds_fill(int64_t *cur_timeout)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
|
|
|
GMainContext *context = g_main_context_default();
|
2012-03-20 10:49:17 +01:00
|
|
|
int timeout = 0;
|
2013-08-21 17:02:54 +02:00
|
|
|
int64_t timeout_ns;
|
2013-02-20 11:28:26 +01:00
|
|
|
int n;
|
2011-09-13 10:30:52 +02:00
|
|
|
|
|
|
|
g_main_context_prepare(context, &max_priority);
|
|
|
|
|
2013-02-20 11:28:26 +01:00
|
|
|
glib_pollfds_idx = gpollfds->len;
|
|
|
|
n = glib_n_poll_fds;
|
|
|
|
do {
|
|
|
|
GPollFD *pfds;
|
|
|
|
glib_n_poll_fds = n;
|
|
|
|
g_array_set_size(gpollfds, glib_pollfds_idx + glib_n_poll_fds);
|
|
|
|
pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx);
|
|
|
|
n = g_main_context_query(context, max_priority, &timeout, pfds,
|
|
|
|
glib_n_poll_fds);
|
|
|
|
} while (n != glib_n_poll_fds);
|
2011-09-13 10:30:52 +02:00
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
if (timeout < 0) {
|
|
|
|
timeout_ns = -1;
|
|
|
|
} else {
|
|
|
|
timeout_ns = (int64_t)timeout * (int64_t)SCALE_MS;
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
2013-08-21 17:02:54 +02:00
|
|
|
|
|
|
|
*cur_timeout = qemu_soonest_timeout(timeout_ns, *cur_timeout);
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
|
|
|
|
2013-02-20 11:28:26 +01:00
|
|
|
static void glib_pollfds_poll(void)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
|
|
|
GMainContext *context = g_main_context_default();
|
2013-02-20 11:28:26 +01:00
|
|
|
GPollFD *pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx);
|
2011-09-13 10:30:52 +02:00
|
|
|
|
2013-02-20 11:28:26 +01:00
|
|
|
if (g_main_context_check(context, max_priority, pfds, glib_n_poll_fds)) {
|
2011-09-13 10:30:52 +02:00
|
|
|
g_main_context_dispatch(context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 15:46:00 +02:00
|
|
|
#define MAX_MAIN_LOOP_SPIN (1000)
|
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
static int os_host_main_loop_wait(int64_t timeout)
|
2012-03-20 10:49:18 +01:00
|
|
|
{
|
main-loop: Acquire main_context lock around os_host_main_loop_wait.
When running virt-rescue the serial console hangs from time to time.
Virt-rescue runs an ordinary Linux kernel "appliance", but there is
only a single idle process running inside, so the qemu main loop is
largely idle. With virt-rescue >= 1.37 you may be able to observe the
hang by doing:
$ virt-rescue -e ^] --scratch
><rescue> while true; do ls -l /usr/bin; done
The hang in virt-rescue can be resolved by pressing a key on the
serial console.
Possibly with the same root cause, we also observed hangs during very
early boot of regular Linux VMs with a serial console. Those hangs
are extremely rare, but you may be able to observe them by running
this command on baremetal for a sufficiently long time:
$ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done
(Check in /tmp/log that the failure was caused by a hang during early
boot, and not some other reason)
During investigation of this bug, Paolo Bonzini wrote:
> glib is expecting QEMU to use g_main_context_acquire around accesses to
> GMainContext. However QEMU is not doing that, instead it is taking its
> own mutex. So we should add g_main_context_acquire and
> g_main_context_release in the two implementations of
> os_host_main_loop_wait; these should undo the effect of Frediano's
> glib patch.
This patch exactly implements Paolo's suggestion in that paragraph.
This fixes the serial console hang in my testing, across 3 different
physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours
of automated testing. I wasn't able to reproduce the early boot hangs
(but as noted above, these are extremely rare in any case).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20170331205133.23906-1-rjones@redhat.com>
[Paolo: this is actually a glib bug: recent glib versions are also
expecting g_main_context_acquire around g_poll---but that is not
documented and probably not even intended].
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-31 22:51:33 +02:00
|
|
|
GMainContext *context = g_main_context_default();
|
2012-03-20 10:49:18 +01:00
|
|
|
int ret;
|
|
|
|
|
main-loop: Acquire main_context lock around os_host_main_loop_wait.
When running virt-rescue the serial console hangs from time to time.
Virt-rescue runs an ordinary Linux kernel "appliance", but there is
only a single idle process running inside, so the qemu main loop is
largely idle. With virt-rescue >= 1.37 you may be able to observe the
hang by doing:
$ virt-rescue -e ^] --scratch
><rescue> while true; do ls -l /usr/bin; done
The hang in virt-rescue can be resolved by pressing a key on the
serial console.
Possibly with the same root cause, we also observed hangs during very
early boot of regular Linux VMs with a serial console. Those hangs
are extremely rare, but you may be able to observe them by running
this command on baremetal for a sufficiently long time:
$ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done
(Check in /tmp/log that the failure was caused by a hang during early
boot, and not some other reason)
During investigation of this bug, Paolo Bonzini wrote:
> glib is expecting QEMU to use g_main_context_acquire around accesses to
> GMainContext. However QEMU is not doing that, instead it is taking its
> own mutex. So we should add g_main_context_acquire and
> g_main_context_release in the two implementations of
> os_host_main_loop_wait; these should undo the effect of Frediano's
> glib patch.
This patch exactly implements Paolo's suggestion in that paragraph.
This fixes the serial console hang in my testing, across 3 different
physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours
of automated testing. I wasn't able to reproduce the early boot hangs
(but as noted above, these are extremely rare in any case).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20170331205133.23906-1-rjones@redhat.com>
[Paolo: this is actually a glib bug: recent glib versions are also
expecting g_main_context_acquire around g_poll---but that is not
documented and probably not even intended].
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-31 22:51:33 +02:00
|
|
|
g_main_context_acquire(context);
|
|
|
|
|
2013-02-20 11:28:26 +01:00
|
|
|
glib_pollfds_fill(&timeout);
|
2012-03-20 10:49:18 +01:00
|
|
|
|
2018-02-27 10:52:48 +01:00
|
|
|
qemu_mutex_unlock_iothread();
|
|
|
|
replay_mutex_unlock();
|
2012-03-20 10:49:18 +01:00
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout);
|
2013-02-20 11:28:25 +01:00
|
|
|
|
2018-02-27 10:52:48 +01:00
|
|
|
replay_mutex_lock();
|
|
|
|
qemu_mutex_lock_iothread();
|
2012-03-20 10:49:18 +01:00
|
|
|
|
2013-02-20 11:28:26 +01:00
|
|
|
glib_pollfds_poll();
|
main-loop: Acquire main_context lock around os_host_main_loop_wait.
When running virt-rescue the serial console hangs from time to time.
Virt-rescue runs an ordinary Linux kernel "appliance", but there is
only a single idle process running inside, so the qemu main loop is
largely idle. With virt-rescue >= 1.37 you may be able to observe the
hang by doing:
$ virt-rescue -e ^] --scratch
><rescue> while true; do ls -l /usr/bin; done
The hang in virt-rescue can be resolved by pressing a key on the
serial console.
Possibly with the same root cause, we also observed hangs during very
early boot of regular Linux VMs with a serial console. Those hangs
are extremely rare, but you may be able to observe them by running
this command on baremetal for a sufficiently long time:
$ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done
(Check in /tmp/log that the failure was caused by a hang during early
boot, and not some other reason)
During investigation of this bug, Paolo Bonzini wrote:
> glib is expecting QEMU to use g_main_context_acquire around accesses to
> GMainContext. However QEMU is not doing that, instead it is taking its
> own mutex. So we should add g_main_context_acquire and
> g_main_context_release in the two implementations of
> os_host_main_loop_wait; these should undo the effect of Frediano's
> glib patch.
This patch exactly implements Paolo's suggestion in that paragraph.
This fixes the serial console hang in my testing, across 3 different
physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours
of automated testing. I wasn't able to reproduce the early boot hangs
(but as noted above, these are extremely rare in any case).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20170331205133.23906-1-rjones@redhat.com>
[Paolo: this is actually a glib bug: recent glib versions are also
expecting g_main_context_acquire around g_poll---but that is not
documented and probably not even intended].
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-31 22:51:33 +02:00
|
|
|
|
|
|
|
g_main_context_release(context);
|
|
|
|
|
2012-03-20 10:49:18 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
2011-09-13 10:30:52 +02:00
|
|
|
/***********************************************************/
|
|
|
|
/* Polling handling */
|
|
|
|
|
|
|
|
typedef struct PollingEntry {
|
|
|
|
PollingFunc *func;
|
|
|
|
void *opaque;
|
|
|
|
struct PollingEntry *next;
|
|
|
|
} PollingEntry;
|
|
|
|
|
|
|
|
static PollingEntry *first_polling_entry;
|
|
|
|
|
|
|
|
int qemu_add_polling_cb(PollingFunc *func, void *opaque)
|
|
|
|
{
|
|
|
|
PollingEntry **ppe, *pe;
|
|
|
|
pe = g_malloc0(sizeof(PollingEntry));
|
|
|
|
pe->func = func;
|
|
|
|
pe->opaque = opaque;
|
|
|
|
for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
|
|
|
|
*ppe = pe;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_del_polling_cb(PollingFunc *func, void *opaque)
|
|
|
|
{
|
|
|
|
PollingEntry **ppe, *pe;
|
|
|
|
for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
|
|
|
|
pe = *ppe;
|
|
|
|
if (pe->func == func && pe->opaque == opaque) {
|
|
|
|
*ppe = pe->next;
|
|
|
|
g_free(pe);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************/
|
|
|
|
/* Wait objects support */
|
|
|
|
typedef struct WaitObjects {
|
|
|
|
int num;
|
2012-03-20 10:49:20 +01:00
|
|
|
int revents[MAXIMUM_WAIT_OBJECTS + 1];
|
2011-09-13 10:30:52 +02:00
|
|
|
HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
|
|
|
|
WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
|
|
|
|
void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
|
|
|
|
} WaitObjects;
|
|
|
|
|
|
|
|
static WaitObjects wait_objects = {0};
|
|
|
|
|
|
|
|
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
|
|
|
|
{
|
|
|
|
WaitObjects *w = &wait_objects;
|
|
|
|
if (w->num >= MAXIMUM_WAIT_OBJECTS) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
w->events[w->num] = handle;
|
|
|
|
w->func[w->num] = func;
|
|
|
|
w->opaque[w->num] = opaque;
|
2012-03-20 10:49:20 +01:00
|
|
|
w->revents[w->num] = 0;
|
2011-09-13 10:30:52 +02:00
|
|
|
w->num++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
|
|
|
|
{
|
|
|
|
int i, found;
|
|
|
|
WaitObjects *w = &wait_objects;
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
for (i = 0; i < w->num; i++) {
|
|
|
|
if (w->events[i] == handle) {
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
if (found) {
|
|
|
|
w->events[i] = w->events[i + 1];
|
|
|
|
w->func[i] = w->func[i + 1];
|
|
|
|
w->opaque[i] = w->opaque[i + 1];
|
2012-03-20 10:49:20 +01:00
|
|
|
w->revents[i] = w->revents[i + 1];
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found) {
|
|
|
|
w->num--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-20 10:49:19 +01:00
|
|
|
void qemu_fd_register(int fd)
|
|
|
|
{
|
2010-05-24 17:27:14 +02:00
|
|
|
WSAEventSelect(fd, event_notifier_get_handle(&qemu_aio_context->notifier),
|
|
|
|
FD_READ | FD_ACCEPT | FD_CLOSE |
|
2012-03-20 10:49:19 +01:00
|
|
|
FD_CONNECT | FD_WRITE | FD_OOB);
|
|
|
|
}
|
|
|
|
|
2013-02-20 11:28:25 +01:00
|
|
|
static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds,
|
|
|
|
fd_set *xfds)
|
|
|
|
{
|
|
|
|
int nfds = -1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pollfds->len; i++) {
|
|
|
|
GPollFD *pfd = &g_array_index(pollfds, GPollFD, i);
|
|
|
|
int fd = pfd->fd;
|
|
|
|
int events = pfd->events;
|
2013-05-16 17:36:00 +02:00
|
|
|
if (events & G_IO_IN) {
|
2013-02-20 11:28:25 +01:00
|
|
|
FD_SET(fd, rfds);
|
|
|
|
nfds = MAX(nfds, fd);
|
|
|
|
}
|
2013-05-16 17:36:00 +02:00
|
|
|
if (events & G_IO_OUT) {
|
2013-02-20 11:28:25 +01:00
|
|
|
FD_SET(fd, wfds);
|
|
|
|
nfds = MAX(nfds, fd);
|
|
|
|
}
|
|
|
|
if (events & G_IO_PRI) {
|
|
|
|
FD_SET(fd, xfds);
|
|
|
|
nfds = MAX(nfds, fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nfds;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds,
|
|
|
|
fd_set *wfds, fd_set *xfds)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pollfds->len; i++) {
|
|
|
|
GPollFD *pfd = &g_array_index(pollfds, GPollFD, i);
|
|
|
|
int fd = pfd->fd;
|
|
|
|
int revents = 0;
|
|
|
|
|
|
|
|
if (FD_ISSET(fd, rfds)) {
|
2013-05-16 17:36:00 +02:00
|
|
|
revents |= G_IO_IN;
|
2013-02-20 11:28:25 +01:00
|
|
|
}
|
|
|
|
if (FD_ISSET(fd, wfds)) {
|
2013-05-16 17:36:00 +02:00
|
|
|
revents |= G_IO_OUT;
|
2013-02-20 11:28:25 +01:00
|
|
|
}
|
|
|
|
if (FD_ISSET(fd, xfds)) {
|
|
|
|
revents |= G_IO_PRI;
|
|
|
|
}
|
|
|
|
pfd->revents = revents & pfd->events;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
static int os_host_main_loop_wait(int64_t timeout)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
2012-03-20 10:49:21 +01:00
|
|
|
GMainContext *context = g_main_context_default();
|
2013-02-20 11:28:26 +01:00
|
|
|
GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
|
2013-02-20 11:28:24 +01:00
|
|
|
int select_ret = 0;
|
2013-02-20 11:28:26 +01:00
|
|
|
int g_poll_ret, ret, i, n_poll_fds;
|
2011-09-13 10:30:52 +02:00
|
|
|
PollingEntry *pe;
|
2012-03-20 10:49:19 +01:00
|
|
|
WaitObjects *w = &wait_objects;
|
2012-04-27 17:02:08 +02:00
|
|
|
gint poll_timeout;
|
2013-08-21 17:02:54 +02:00
|
|
|
int64_t poll_timeout_ns;
|
2012-03-20 10:49:18 +01:00
|
|
|
static struct timeval tv0;
|
2013-02-20 11:28:30 +01:00
|
|
|
fd_set rfds, wfds, xfds;
|
|
|
|
int nfds;
|
2011-09-13 10:30:52 +02:00
|
|
|
|
main-loop: Acquire main_context lock around os_host_main_loop_wait.
When running virt-rescue the serial console hangs from time to time.
Virt-rescue runs an ordinary Linux kernel "appliance", but there is
only a single idle process running inside, so the qemu main loop is
largely idle. With virt-rescue >= 1.37 you may be able to observe the
hang by doing:
$ virt-rescue -e ^] --scratch
><rescue> while true; do ls -l /usr/bin; done
The hang in virt-rescue can be resolved by pressing a key on the
serial console.
Possibly with the same root cause, we also observed hangs during very
early boot of regular Linux VMs with a serial console. Those hangs
are extremely rare, but you may be able to observe them by running
this command on baremetal for a sufficiently long time:
$ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done
(Check in /tmp/log that the failure was caused by a hang during early
boot, and not some other reason)
During investigation of this bug, Paolo Bonzini wrote:
> glib is expecting QEMU to use g_main_context_acquire around accesses to
> GMainContext. However QEMU is not doing that, instead it is taking its
> own mutex. So we should add g_main_context_acquire and
> g_main_context_release in the two implementations of
> os_host_main_loop_wait; these should undo the effect of Frediano's
> glib patch.
This patch exactly implements Paolo's suggestion in that paragraph.
This fixes the serial console hang in my testing, across 3 different
physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours
of automated testing. I wasn't able to reproduce the early boot hangs
(but as noted above, these are extremely rare in any case).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20170331205133.23906-1-rjones@redhat.com>
[Paolo: this is actually a glib bug: recent glib versions are also
expecting g_main_context_acquire around g_poll---but that is not
documented and probably not even intended].
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-31 22:51:33 +02:00
|
|
|
g_main_context_acquire(context);
|
|
|
|
|
2011-09-13 10:30:52 +02:00
|
|
|
/* XXX: need to suppress polling by better using win32 events */
|
|
|
|
ret = 0;
|
|
|
|
for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
|
|
|
|
ret |= pe->func(pe->opaque);
|
|
|
|
}
|
2012-03-20 10:49:19 +01:00
|
|
|
if (ret != 0) {
|
main-loop: Acquire main_context lock around os_host_main_loop_wait.
When running virt-rescue the serial console hangs from time to time.
Virt-rescue runs an ordinary Linux kernel "appliance", but there is
only a single idle process running inside, so the qemu main loop is
largely idle. With virt-rescue >= 1.37 you may be able to observe the
hang by doing:
$ virt-rescue -e ^] --scratch
><rescue> while true; do ls -l /usr/bin; done
The hang in virt-rescue can be resolved by pressing a key on the
serial console.
Possibly with the same root cause, we also observed hangs during very
early boot of regular Linux VMs with a serial console. Those hangs
are extremely rare, but you may be able to observe them by running
this command on baremetal for a sufficiently long time:
$ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done
(Check in /tmp/log that the failure was caused by a hang during early
boot, and not some other reason)
During investigation of this bug, Paolo Bonzini wrote:
> glib is expecting QEMU to use g_main_context_acquire around accesses to
> GMainContext. However QEMU is not doing that, instead it is taking its
> own mutex. So we should add g_main_context_acquire and
> g_main_context_release in the two implementations of
> os_host_main_loop_wait; these should undo the effect of Frediano's
> glib patch.
This patch exactly implements Paolo's suggestion in that paragraph.
This fixes the serial console hang in my testing, across 3 different
physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours
of automated testing. I wasn't able to reproduce the early boot hangs
(but as noted above, these are extremely rare in any case).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20170331205133.23906-1-rjones@redhat.com>
[Paolo: this is actually a glib bug: recent glib versions are also
expecting g_main_context_acquire around g_poll---but that is not
documented and probably not even intended].
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-31 22:51:33 +02:00
|
|
|
g_main_context_release(context);
|
2012-03-20 10:49:19 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2011-09-13 10:30:52 +02:00
|
|
|
|
2013-05-16 17:36:01 +02:00
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_ZERO(&wfds);
|
|
|
|
FD_ZERO(&xfds);
|
|
|
|
nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds);
|
|
|
|
if (nfds >= 0) {
|
|
|
|
select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
|
|
|
|
if (select_ret != 0) {
|
|
|
|
timeout = 0;
|
|
|
|
}
|
|
|
|
if (select_ret > 0) {
|
|
|
|
pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-20 10:49:21 +01:00
|
|
|
g_main_context_prepare(context, &max_priority);
|
2012-04-27 17:02:08 +02:00
|
|
|
n_poll_fds = g_main_context_query(context, max_priority, &poll_timeout,
|
2012-03-20 10:49:21 +01:00
|
|
|
poll_fds, ARRAY_SIZE(poll_fds));
|
2019-06-19 21:14:47 +02:00
|
|
|
g_assert(n_poll_fds + w->num <= ARRAY_SIZE(poll_fds));
|
2012-03-20 10:49:21 +01:00
|
|
|
|
2012-03-20 10:49:20 +01:00
|
|
|
for (i = 0; i < w->num; i++) {
|
2012-04-12 20:42:34 +02:00
|
|
|
poll_fds[n_poll_fds + i].fd = (DWORD_PTR)w->events[i];
|
2012-03-20 10:49:21 +01:00
|
|
|
poll_fds[n_poll_fds + i].events = G_IO_IN;
|
2012-03-20 10:49:20 +01:00
|
|
|
}
|
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
if (poll_timeout < 0) {
|
|
|
|
poll_timeout_ns = -1;
|
|
|
|
} else {
|
|
|
|
poll_timeout_ns = (int64_t)poll_timeout * (int64_t)SCALE_MS;
|
2012-04-29 19:15:02 +02:00
|
|
|
}
|
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
poll_timeout_ns = qemu_soonest_timeout(poll_timeout_ns, timeout);
|
|
|
|
|
2012-03-20 10:49:19 +01:00
|
|
|
qemu_mutex_unlock_iothread();
|
2018-02-27 10:52:48 +01:00
|
|
|
|
|
|
|
replay_mutex_unlock();
|
|
|
|
|
2013-08-21 17:02:54 +02:00
|
|
|
g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns);
|
|
|
|
|
2018-02-27 10:52:48 +01:00
|
|
|
replay_mutex_lock();
|
|
|
|
|
2012-03-20 10:49:19 +01:00
|
|
|
qemu_mutex_lock_iothread();
|
2013-01-08 16:30:56 +01:00
|
|
|
if (g_poll_ret > 0) {
|
2012-03-20 10:49:20 +01:00
|
|
|
for (i = 0; i < w->num; i++) {
|
2012-03-20 10:49:21 +01:00
|
|
|
w->revents[i] = poll_fds[n_poll_fds + i].revents;
|
2012-03-20 10:49:19 +01:00
|
|
|
}
|
2012-03-20 10:49:20 +01:00
|
|
|
for (i = 0; i < w->num; i++) {
|
|
|
|
if (w->revents[i] && w->func[i]) {
|
|
|
|
w->func[i](w->opaque[i]);
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-20 10:49:21 +01:00
|
|
|
if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
|
|
|
|
g_main_context_dispatch(context);
|
|
|
|
}
|
|
|
|
|
main-loop: Acquire main_context lock around os_host_main_loop_wait.
When running virt-rescue the serial console hangs from time to time.
Virt-rescue runs an ordinary Linux kernel "appliance", but there is
only a single idle process running inside, so the qemu main loop is
largely idle. With virt-rescue >= 1.37 you may be able to observe the
hang by doing:
$ virt-rescue -e ^] --scratch
><rescue> while true; do ls -l /usr/bin; done
The hang in virt-rescue can be resolved by pressing a key on the
serial console.
Possibly with the same root cause, we also observed hangs during very
early boot of regular Linux VMs with a serial console. Those hangs
are extremely rare, but you may be able to observe them by running
this command on baremetal for a sufficiently long time:
$ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done
(Check in /tmp/log that the failure was caused by a hang during early
boot, and not some other reason)
During investigation of this bug, Paolo Bonzini wrote:
> glib is expecting QEMU to use g_main_context_acquire around accesses to
> GMainContext. However QEMU is not doing that, instead it is taking its
> own mutex. So we should add g_main_context_acquire and
> g_main_context_release in the two implementations of
> os_host_main_loop_wait; these should undo the effect of Frediano's
> glib patch.
This patch exactly implements Paolo's suggestion in that paragraph.
This fixes the serial console hang in my testing, across 3 different
physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours
of automated testing. I wasn't able to reproduce the early boot hangs
(but as noted above, these are extremely rare in any case).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20170331205133.23906-1-rjones@redhat.com>
[Paolo: this is actually a glib bug: recent glib versions are also
expecting g_main_context_acquire around g_poll---but that is not
documented and probably not even intended].
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-31 22:51:33 +02:00
|
|
|
g_main_context_release(context);
|
|
|
|
|
2013-01-08 16:30:56 +01:00
|
|
|
return select_ret || g_poll_ret;
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-01-17 12:43:55 +01:00
|
|
|
static NotifierList main_loop_poll_notifiers =
|
|
|
|
NOTIFIER_LIST_INITIALIZER(main_loop_poll_notifiers);
|
|
|
|
|
|
|
|
void main_loop_poll_add_notifier(Notifier *notify)
|
|
|
|
{
|
|
|
|
notifier_list_add(&main_loop_poll_notifiers, notify);
|
|
|
|
}
|
|
|
|
|
|
|
|
void main_loop_poll_remove_notifier(Notifier *notify)
|
|
|
|
{
|
|
|
|
notifier_remove(notify);
|
|
|
|
}
|
|
|
|
|
2017-06-27 19:32:49 +02:00
|
|
|
void main_loop_wait(int nonblocking)
|
2011-09-13 10:30:52 +02:00
|
|
|
{
|
2019-01-17 12:43:55 +01:00
|
|
|
MainLoopPoll mlpoll = {
|
|
|
|
.state = MAIN_LOOP_POLL_FILL,
|
|
|
|
.timeout = UINT32_MAX,
|
|
|
|
.pollfds = gpollfds,
|
|
|
|
};
|
2012-04-13 20:35:04 +02:00
|
|
|
int ret;
|
2013-08-21 17:02:54 +02:00
|
|
|
int64_t timeout_ns;
|
2011-09-13 10:30:52 +02:00
|
|
|
|
|
|
|
if (nonblocking) {
|
2019-01-17 12:43:55 +01:00
|
|
|
mlpoll.timeout = 0;
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* poll any events */
|
2013-02-20 11:28:25 +01:00
|
|
|
g_array_set_size(gpollfds, 0); /* reset for new iteration */
|
2011-09-13 10:30:52 +02:00
|
|
|
/* XXX: separate device handlers from system ones */
|
2019-01-17 12:43:55 +01:00
|
|
|
notifier_list_notify(&main_loop_poll_notifiers, &mlpoll);
|
2013-08-21 17:02:54 +02:00
|
|
|
|
2019-01-17 12:43:55 +01:00
|
|
|
if (mlpoll.timeout == UINT32_MAX) {
|
2013-08-21 17:02:54 +02:00
|
|
|
timeout_ns = -1;
|
|
|
|
} else {
|
2019-01-17 12:43:55 +01:00
|
|
|
timeout_ns = (uint64_t)mlpoll.timeout * (int64_t)(SCALE_MS);
|
2013-08-21 17:02:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
timeout_ns = qemu_soonest_timeout(timeout_ns,
|
|
|
|
timerlistgroup_deadline_ns(
|
|
|
|
&main_loop_tlg));
|
|
|
|
|
|
|
|
ret = os_host_main_loop_wait(timeout_ns);
|
2019-01-17 12:43:55 +01:00
|
|
|
mlpoll.state = ret < 0 ? MAIN_LOOP_POLL_ERR : MAIN_LOOP_POLL_OK;
|
|
|
|
notifier_list_notify(&main_loop_poll_notifiers, &mlpoll);
|
2011-09-13 10:30:52 +02:00
|
|
|
|
2020-08-19 13:17:19 +02:00
|
|
|
if (icount_enabled()) {
|
|
|
|
/*
|
|
|
|
* CPU thread can infinitely wait for event after
|
|
|
|
* missing the warp
|
|
|
|
*/
|
2020-08-31 16:18:34 +02:00
|
|
|
icount_start_warp_timer();
|
2020-08-19 13:17:19 +02:00
|
|
|
}
|
2013-08-21 17:03:02 +02:00
|
|
|
qemu_clock_run_all_timers();
|
2011-09-13 10:30:52 +02:00
|
|
|
}
|
2012-10-29 23:45:23 +01:00
|
|
|
|
|
|
|
/* Functions to operate on the main QEMU AioContext. */
|
|
|
|
|
|
|
|
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
|
|
|
|
{
|
|
|
|
return aio_bh_new(qemu_aio_context, cb, opaque);
|
|
|
|
}
|
2019-07-12 19:34:35 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Functions to operate on the I/O handler AioContext.
|
|
|
|
* This context runs on top of main loop. We can't reuse qemu_aio_context
|
|
|
|
* because iohandlers mustn't be polled by aio_poll(qemu_aio_context).
|
|
|
|
*/
|
|
|
|
static AioContext *iohandler_ctx;
|
|
|
|
|
|
|
|
static void iohandler_init(void)
|
|
|
|
{
|
|
|
|
if (!iohandler_ctx) {
|
|
|
|
iohandler_ctx = aio_context_new(&error_abort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AioContext *iohandler_get_aio_context(void)
|
|
|
|
{
|
|
|
|
iohandler_init();
|
|
|
|
return iohandler_ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
GSource *iohandler_get_g_source(void)
|
|
|
|
{
|
|
|
|
iohandler_init();
|
|
|
|
return aio_get_g_source(iohandler_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_set_fd_handler(int fd,
|
|
|
|
IOHandler *fd_read,
|
|
|
|
IOHandler *fd_write,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
iohandler_init();
|
|
|
|
aio_set_fd_handler(iohandler_ctx, fd, false,
|
|
|
|
fd_read, fd_write, NULL, opaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_notifier_set_handler(EventNotifier *e,
|
|
|
|
EventNotifierHandler *handler)
|
|
|
|
{
|
|
|
|
iohandler_init();
|
|
|
|
aio_set_event_notifier(iohandler_ctx, e, false,
|
|
|
|
handler, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reaping of zombies. right now we're not passing the status to
|
|
|
|
anyone, but it would be possible to add a callback. */
|
|
|
|
#ifndef _WIN32
|
|
|
|
typedef struct ChildProcessRecord {
|
|
|
|
int pid;
|
|
|
|
QLIST_ENTRY(ChildProcessRecord) next;
|
|
|
|
} ChildProcessRecord;
|
|
|
|
|
|
|
|
static QLIST_HEAD(, ChildProcessRecord) child_watches =
|
|
|
|
QLIST_HEAD_INITIALIZER(child_watches);
|
|
|
|
|
|
|
|
static QEMUBH *sigchld_bh;
|
|
|
|
|
|
|
|
static void sigchld_handler(int signal)
|
|
|
|
{
|
|
|
|
qemu_bh_schedule(sigchld_bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sigchld_bh_handler(void *opaque)
|
|
|
|
{
|
|
|
|
ChildProcessRecord *rec, *next;
|
|
|
|
|
|
|
|
QLIST_FOREACH_SAFE(rec, &child_watches, next, next) {
|
|
|
|
if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) {
|
|
|
|
QLIST_REMOVE(rec, next);
|
|
|
|
g_free(rec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qemu_init_child_watch(void)
|
|
|
|
{
|
|
|
|
struct sigaction act;
|
|
|
|
sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
|
|
|
|
|
|
|
|
memset(&act, 0, sizeof(act));
|
|
|
|
act.sa_handler = sigchld_handler;
|
|
|
|
act.sa_flags = SA_NOCLDSTOP;
|
|
|
|
sigaction(SIGCHLD, &act, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemu_add_child_watch(pid_t pid)
|
|
|
|
{
|
|
|
|
ChildProcessRecord *rec;
|
|
|
|
|
|
|
|
if (!sigchld_bh) {
|
|
|
|
qemu_init_child_watch();
|
|
|
|
}
|
|
|
|
|
|
|
|
QLIST_FOREACH(rec, &child_watches, next) {
|
|
|
|
if (rec->pid == pid) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rec = g_malloc0(sizeof(ChildProcessRecord));
|
|
|
|
rec->pid = pid;
|
|
|
|
QLIST_INSERT_HEAD(&child_watches, rec, next);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|