#include "qemu-config.h"
#include "qemu-objects.h"
#include "qemu-options.h"
+#include "qmp-commands.h"
+#include "main-loop.h"
#ifdef CONFIG_VIRTFS
#include "fsdev/qemu-fsdev.h"
#endif
uint64_t node_mem[MAX_NODES];
uint64_t node_cpumask[MAX_NODES];
-static QEMUTimer *nographic_timer;
-
uint8_t qemu_uuid[16];
static QEMUBootSetHandler *boot_set_handler;
/***********************************************************/
/* QEMU state */
-static RunState current_run_state = RSTATE_NO_STATE;
+static RunState current_run_state = RUN_STATE_PRELAUNCH;
typedef struct {
RunState from;
static const RunStateTransition runstate_transitions_def[] = {
/* from -> to */
- { RSTATE_NO_STATE, RSTATE_RUNNING },
- { RSTATE_NO_STATE, RSTATE_IN_MIGRATE },
- { RSTATE_NO_STATE, RSTATE_PRE_LAUNCH },
-
- { RSTATE_DEBUG, RSTATE_RUNNING },
+ { RUN_STATE_DEBUG, RUN_STATE_RUNNING },
- { RSTATE_IN_MIGRATE, RSTATE_RUNNING },
- { RSTATE_IN_MIGRATE, RSTATE_PRE_LAUNCH },
+ { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING },
+ { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
- { RSTATE_PANICKED, RSTATE_PAUSED },
+ { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
+ { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
- { RSTATE_IO_ERROR, RSTATE_RUNNING },
+ { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
+ { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE },
- { RSTATE_PAUSED, RSTATE_RUNNING },
+ { RUN_STATE_PAUSED, RUN_STATE_RUNNING },
+ { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE },
- { RSTATE_POST_MIGRATE, RSTATE_RUNNING },
+ { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
+ { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
- { RSTATE_PRE_LAUNCH, RSTATE_RUNNING },
- { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
- { RSTATE_PRE_MIGRATE, RSTATE_RUNNING },
- { RSTATE_PRE_MIGRATE, RSTATE_POST_MIGRATE },
+ { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
+ { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
- { RSTATE_RESTORE, RSTATE_RUNNING },
+ { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
- { RSTATE_RUNNING, RSTATE_DEBUG },
- { RSTATE_RUNNING, RSTATE_PANICKED },
- { RSTATE_RUNNING, RSTATE_IO_ERROR },
- { RSTATE_RUNNING, RSTATE_PAUSED },
- { RSTATE_RUNNING, RSTATE_PRE_MIGRATE },
- { RSTATE_RUNNING, RSTATE_RESTORE },
- { RSTATE_RUNNING, RSTATE_SAVEVM },
- { RSTATE_RUNNING, RSTATE_SHUTDOWN },
- { RSTATE_RUNNING, RSTATE_WATCHDOG },
+ { RUN_STATE_RUNNING, RUN_STATE_DEBUG },
+ { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR },
+ { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR },
+ { RUN_STATE_RUNNING, RUN_STATE_PAUSED },
+ { RUN_STATE_RUNNING, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_RUNNING, RUN_STATE_RESTORE_VM },
+ { RUN_STATE_RUNNING, RUN_STATE_SAVE_VM },
+ { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN },
+ { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
- { RSTATE_SAVEVM, RSTATE_RUNNING },
+ { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
- { RSTATE_SHUTDOWN, RSTATE_PAUSED },
+ { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
+ { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE },
- { RSTATE_WATCHDOG, RSTATE_RUNNING },
+ { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
+ { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
- { RSTATE_MAX, RSTATE_MAX },
+ { RUN_STATE_MAX, RUN_STATE_MAX },
};
-static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_MAX];
-
-static const char *const runstate_name_tbl[RSTATE_MAX] = {
- [RSTATE_DEBUG] = "debug",
- [RSTATE_IN_MIGRATE] = "incoming-migration",
- [RSTATE_PANICKED] = "internal-error",
- [RSTATE_IO_ERROR] = "io-error",
- [RSTATE_PAUSED] = "paused",
- [RSTATE_POST_MIGRATE] = "post-migrate",
- [RSTATE_PRE_LAUNCH] = "prelaunch",
- [RSTATE_PRE_MIGRATE] = "finish-migrate",
- [RSTATE_RESTORE] = "restore-vm",
- [RSTATE_RUNNING] = "running",
- [RSTATE_SAVEVM] = "save-vm",
- [RSTATE_SHUTDOWN] = "shutdown",
- [RSTATE_WATCHDOG] = "watchdog",
-};
+static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX];
bool runstate_check(RunState state)
{
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
- for (p = &runstate_transitions_def[0]; p->from != RSTATE_MAX; p++) {
+ for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) {
runstate_valid_transitions[p->from][p->to] = true;
}
}
/* This function will abort() on invalid state transitions */
void runstate_set(RunState new_state)
{
- if (new_state >= RSTATE_MAX ||
- !runstate_valid_transitions[current_run_state][new_state]) {
- fprintf(stderr, "invalid runstate transition\n");
+ assert(new_state < RUN_STATE_MAX);
+
+ if (!runstate_valid_transitions[current_run_state][new_state]) {
+ fprintf(stderr, "ERROR: invalid runstate transition: '%s' -> '%s'\n",
+ RunState_lookup[current_run_state],
+ RunState_lookup[new_state]);
abort();
}
current_run_state = new_state;
}
-const char *runstate_as_string(void)
+int runstate_is_running(void)
{
- assert(current_run_state > RSTATE_NO_STATE &&
- current_run_state < RSTATE_MAX);
- return runstate_name_tbl[current_run_state];
+ return runstate_check(RUN_STATE_RUNNING);
}
-int runstate_is_running(void)
+StatusInfo *qmp_query_status(Error **errp)
{
- return runstate_check(RSTATE_RUNNING);
+ StatusInfo *info = g_malloc0(sizeof(*info));
+
+ info->running = runstate_is_running();
+ info->singlestep = singlestep;
+ info->status = current_run_state;
+
+ return info;
}
/***********************************************************/
DisplayState *ds = opaque;
DisplayChangeListener *dcl = ds->listeners;
- qemu_flush_coalesced_mmio_buffer();
dpy_refresh(ds);
while (dcl != NULL) {
qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock));
}
-static void nographic_update(void *opaque)
-{
- uint64_t interval = GUI_REFRESH_INTERVAL;
-
- qemu_flush_coalesced_mmio_buffer();
- qemu_mod_timer(nographic_timer, interval + qemu_get_clock_ms(rt_clock));
-}
-
struct vm_change_state_entry {
VMChangeStateHandler *cb;
void *opaque;
{
if (!runstate_is_running()) {
cpu_enable_ticks();
- runstate_set(RSTATE_RUNNING);
- vm_state_notify(1, RSTATE_RUNNING);
+ runstate_set(RUN_STATE_RUNNING);
+ vm_state_notify(1, RUN_STATE_RUNNING);
resume_all_vcpus();
monitor_protocol_event(QEVENT_RESUME, NULL);
}
static pid_t shutdown_pid;
static int powerdown_requested;
static int debug_requested;
-static RunState vmstop_requested = RSTATE_NO_STATE;
+static RunState vmstop_requested = RUN_STATE_MAX;
int qemu_shutdown_requested_get(void)
{
return r;
}
-static RunState qemu_vmstop_requested(void)
+/* We use RUN_STATE_MAX but any invalid value will do */
+static bool qemu_vmstop_requested(RunState *r)
{
- RunState s = vmstop_requested;
- vmstop_requested = RSTATE_NO_STATE;
- return s;
+ if (vmstop_requested < RUN_STATE_MAX) {
+ *r = vmstop_requested;
+ vmstop_requested = RUN_STATE_MAX;
+ return true;
+ }
+
+ return false;
}
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
qemu_notify_event();
}
-static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
-static int n_poll_fds;
-static int max_priority;
+qemu_irq qemu_system_powerdown;
-static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
- fd_set *xfds, struct timeval *tv)
+static bool main_loop_should_exit(void)
{
- GMainContext *context = g_main_context_default();
- int i;
- int timeout = 0, cur_timeout;
-
- g_main_context_prepare(context, &max_priority);
-
- n_poll_fds = g_main_context_query(context, max_priority, &timeout,
- poll_fds, ARRAY_SIZE(poll_fds));
- g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
-
- for (i = 0; i < n_poll_fds; i++) {
- GPollFD *p = &poll_fds[i];
-
- if ((p->events & G_IO_IN)) {
- FD_SET(p->fd, rfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- if ((p->events & G_IO_OUT)) {
- FD_SET(p->fd, wfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- if ((p->events & G_IO_ERR)) {
- FD_SET(p->fd, xfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
+ RunState r;
+ if (qemu_debug_requested()) {
+ vm_stop(RUN_STATE_DEBUG);
}
-
- cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
- if (timeout >= 0 && timeout < cur_timeout) {
- tv->tv_sec = timeout / 1000;
- tv->tv_usec = (timeout % 1000) * 1000;
- }
-}
-
-static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
- bool err)
-{
- GMainContext *context = g_main_context_default();
-
- if (!err) {
- int i;
-
- for (i = 0; i < n_poll_fds; i++) {
- GPollFD *p = &poll_fds[i];
-
- if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
- p->revents |= G_IO_IN;
- }
- if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
- p->revents |= G_IO_OUT;
- }
- if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
- p->revents |= G_IO_ERR;
- }
+ if (qemu_shutdown_requested()) {
+ qemu_kill_report();
+ monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
+ if (no_shutdown) {
+ vm_stop(RUN_STATE_SHUTDOWN);
+ } else {
+ return true;
}
}
-
- if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
- g_main_context_dispatch(context);
- }
-}
-
-int main_loop_wait(int nonblocking)
-{
- fd_set rfds, wfds, xfds;
- int ret, nfds;
- struct timeval tv;
- int timeout;
-
- if (nonblocking)
- timeout = 0;
- else {
- timeout = qemu_calculate_timeout();
- qemu_bh_update_timeout(&timeout);
+ if (qemu_reset_requested()) {
+ pause_all_vcpus();
+ cpu_synchronize_all_states();
+ qemu_system_reset(VMRESET_REPORT);
+ resume_all_vcpus();
+ if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+ runstate_check(RUN_STATE_SHUTDOWN)) {
+ runstate_set(RUN_STATE_PAUSED);
+ }
}
-
- os_host_main_loop_wait(&timeout);
-
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
-
- /* poll any events */
- /* XXX: separate device handlers from system ones */
- nfds = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
-
- qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
- slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
- glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
-
- if (timeout > 0) {
- qemu_mutex_unlock_iothread();
+ if (qemu_powerdown_requested()) {
+ monitor_protocol_event(QEVENT_POWERDOWN, NULL);
+ qemu_irq_raise(qemu_system_powerdown);
}
-
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-
- if (timeout > 0) {
- qemu_mutex_lock_iothread();
+ if (qemu_vmstop_requested(&r)) {
+ vm_stop(r);
}
-
- qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
- slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
- glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
-
- qemu_run_all_timers();
-
- /* Check bottom-halves last in case any of the earlier events triggered
- them. */
- qemu_bh_poll();
-
- return ret;
+ return false;
}
-qemu_irq qemu_system_powerdown;
-
static void main_loop(void)
{
bool nonblocking;
- int last_io __attribute__ ((unused)) = 0;
+ int last_io = 0;
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
- int r;
-
- qemu_main_loop_start();
-
- for (;;) {
+ do {
nonblocking = !kvm_enabled() && last_io > 0;
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#ifdef CONFIG_PROFILER
dev_time += profile_getclock() - ti;
#endif
-
- if (qemu_debug_requested()) {
- vm_stop(RSTATE_DEBUG);
- }
- if (qemu_shutdown_requested()) {
- qemu_kill_report();
- monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
- if (no_shutdown) {
- vm_stop(RSTATE_SHUTDOWN);
- } else
- break;
- }
- if (qemu_reset_requested()) {
- pause_all_vcpus();
- cpu_synchronize_all_states();
- qemu_system_reset(VMRESET_REPORT);
- resume_all_vcpus();
- if (runstate_check(RSTATE_PANICKED) ||
- runstate_check(RSTATE_SHUTDOWN)) {
- runstate_set(RSTATE_PAUSED);
- }
- }
- if (qemu_powerdown_requested()) {
- monitor_protocol_event(QEVENT_POWERDOWN, NULL);
- qemu_irq_raise(qemu_system_powerdown);
- }
- if ((r = qemu_vmstop_requested())) {
- vm_stop(r);
- }
- }
- bdrv_close_all();
- pause_all_vcpus();
+ } while (!main_loop_should_exit());
}
static void version(void)
runstate_init();
init_clocks();
+ rtc_clock = host_clock;
qemu_cache_utils_init(envp);
case QEMU_OPTION_virtfs: {
QemuOpts *fsdev;
QemuOpts *device;
+ const char *writeout;
olist = qemu_find_opts("virtfs");
if (!olist) {
exit(1);
}
- if (qemu_opt_get(opts, "fstype") == NULL ||
+ if (qemu_opt_get(opts, "fsdriver") == NULL ||
qemu_opt_get(opts, "mount_tag") == NULL ||
- qemu_opt_get(opts, "path") == NULL ||
- qemu_opt_get(opts, "security_model") == NULL) {
- fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
- "security_model=[mapped|passthrough|none],"
+ qemu_opt_get(opts, "path") == NULL) {
+ fprintf(stderr, "Usage: -virtfs fsdriver,path=/share_path/,"
+ "[security_model={mapped|passthrough|none}],"
"mount_tag=tag.\n");
exit(1);
}
-
fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
qemu_opt_get(opts, "mount_tag"), 1);
if (!fsdev) {
qemu_opt_get(opts, "mount_tag"));
exit(1);
}
- qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype"));
+
+ writeout = qemu_opt_get(opts, "writeout");
+ if (writeout) {
+#ifdef CONFIG_SYNC_FILE_RANGE
+ qemu_opt_set(fsdev, "writeout", writeout);
+#else
+ fprintf(stderr, "writeout=immediate not supported on "
+ "this platform\n");
+ exit(1);
+#endif
+ }
+ qemu_opt_set(fsdev, "fsdriver", qemu_opt_get(opts, "fsdriver"));
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
qemu_opt_set(fsdev, "security_model",
qemu_opt_get(opts, "security_model"));
configure_accelerator();
+ qemu_init_cpu_loop();
if (qemu_init_main_loop()) {
fprintf(stderr, "qemu_init_main_loop failed\n");
exit(1);
}
dcl = dcl->next;
}
- if (ds->gui_timer == NULL) {
- nographic_timer = qemu_new_timer_ms(rt_clock, nographic_update, NULL);
- qemu_mod_timer(nographic_timer, qemu_get_clock_ms(rt_clock));
- }
text_consoles_set_display(ds);
if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
}
if (incoming) {
- runstate_set(RSTATE_IN_MIGRATE);
+ runstate_set(RUN_STATE_INMIGRATE);
int ret = qemu_start_incoming_migration(incoming);
if (ret < 0) {
fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
}
} else if (autostart) {
vm_start();
- } else {
- runstate_set(RSTATE_PRE_LAUNCH);
}
os_setup_post();
+ resume_all_vcpus();
main_loop();
- quit_timers();
+ bdrv_close_all();
+ pause_all_vcpus();
net_cleanup();
res_free();