#include "qemu-config.h"
#include "qemu-objects.h"
#include "qemu-options.h"
+#include "qmp-commands.h"
#ifdef CONFIG_VIRTFS
#include "fsdev/qemu-fsdev.h"
#endif
#endif
int nb_nics;
NICInfo nd_table[MAX_NICS];
-int vm_running;
int autostart;
-int incoming_expected; /* Started with -incoming and waiting for incoming */
static int rtc_utc = 1;
static int rtc_date_offset = -1; /* -1 means no change */
QEMUClock *rtc_clock;
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;
return 0;
}
+/***********************************************************/
+/* QEMU state */
+
+static RunState current_run_state = RUN_STATE_PRELAUNCH;
+
+typedef struct {
+ RunState from;
+ RunState to;
+} RunStateTransition;
+
+static const RunStateTransition runstate_transitions_def[] = {
+ /* from -> to */
+ { RUN_STATE_DEBUG, RUN_STATE_RUNNING },
+
+ { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING },
+ { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
+
+ { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
+
+ { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
+
+ { RUN_STATE_PAUSED, RUN_STATE_RUNNING },
+
+ { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
+
+ { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_POSTMIGRATE },
+
+ { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
+ { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
+
+ { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
+
+ { 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 },
+
+ { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
+
+ { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
+
+ { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
+
+ { RUN_STATE_MAX, RUN_STATE_MAX },
+};
+
+static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX];
+
+bool runstate_check(RunState state)
+{
+ return current_run_state == state;
+}
+
+void runstate_init(void)
+{
+ const RunStateTransition *p;
+
+ memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
+
+ 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 >= RUN_STATE_MAX ||
+ !runstate_valid_transitions[current_run_state][new_state]) {
+ fprintf(stderr, "invalid runstate transition\n");
+ abort();
+ }
+
+ current_run_state = new_state;
+}
+
+int runstate_is_running(void)
+{
+ return runstate_check(RUN_STATE_RUNNING);
+}
+
+StatusInfo *qmp_query_status(Error **errp)
+{
+ StatusInfo *info = g_malloc0(sizeof(*info));
+
+ info->running = runstate_is_running();
+ info->singlestep = singlestep;
+ info->status = current_run_state;
+
+ return info;
+}
+
/***********************************************************/
/* real time host monotonic timer */
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;
void vm_start(void)
{
- if (!vm_running) {
+ if (!runstate_is_running()) {
cpu_enable_ticks();
- vm_running = 1;
- 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)
{
shutdown_signal = signal;
shutdown_pid = pid;
+ no_shutdown = 0;
qemu_system_shutdown_request();
}
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
- int r;
+ RunState r;
qemu_main_loop_start();
#endif
if (qemu_debug_requested()) {
- vm_stop(RSTATE_DEBUG);
+ vm_stop(RUN_STATE_DEBUG);
}
if (qemu_shutdown_requested()) {
qemu_kill_report();
monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
if (no_shutdown) {
- vm_stop(RSTATE_SHUTDOWN);
+ vm_stop(RUN_STATE_SHUTDOWN);
} else
break;
}
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);
+ }
}
if (qemu_powerdown_requested()) {
monitor_protocol_event(QEVENT_POWERDOWN, NULL);
qemu_irq_raise(qemu_system_powerdown);
}
- if ((r = qemu_vmstop_requested())) {
+ if (qemu_vmstop_requested(&r)) {
vm_stop(r);
}
}
g_mem_set_vtable(&mem_trace);
g_thread_init(NULL);
+ runstate_init();
+
init_clocks();
qemu_cache_utils_init(envp);
break;
case QEMU_OPTION_incoming:
incoming = optarg;
- incoming_expected = true;
break;
case QEMU_OPTION_nodefaults:
default_serial = 0;
}
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(RUN_STATE_INMIGRATE);
int ret = qemu_start_incoming_migration(incoming);
if (ret < 0) {
fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",