From 1dfb4dd993f7122353fb2894f09dfcba894cd7d5 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 29 Jul 2011 14:26:33 -0300 Subject: Replace the VMSTOP macros with a proper state type Today, when notifying a VM state change with vm_state_notify(), we pass a VMSTOP macro as the 'reason' argument. This is not ideal because the VMSTOP macros tell why qemu stopped and not exactly what the current VM state is. One example to demonstrate this problem is that vm_start() calls vm_state_notify() with reason=0, which turns out to be VMSTOP_USER. This commit fixes that by replacing the VMSTOP macros with a proper state type called RunState. Signed-off-by: Luiz Capitulino --- vl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'vl.c') diff --git a/vl.c b/vl.c index b773d2f126..304a499551 100644 --- a/vl.c +++ b/vl.c @@ -1145,14 +1145,14 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) g_free (e); } -void vm_state_notify(int running, int reason) +void vm_state_notify(int running, RunState state) { VMChangeStateEntry *e; - trace_vm_state_notify(running, reason); + trace_vm_state_notify(running, state); for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) { - e->cb(e->opaque, running, reason); + e->cb(e->opaque, running, state); } } @@ -1161,7 +1161,7 @@ void vm_start(void) if (!vm_running) { cpu_enable_ticks(); vm_running = 1; - vm_state_notify(1, 0); + vm_state_notify(1, RSTATE_RUNNING); resume_all_vcpus(); monitor_protocol_event(QEVENT_RESUME, NULL); } @@ -1182,7 +1182,7 @@ static int shutdown_requested, shutdown_signal = -1; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; -static int vmstop_requested; +static RunState vmstop_requested = RSTATE_NO_STATE; int qemu_shutdown_requested_get(void) { @@ -1238,11 +1238,11 @@ static int qemu_debug_requested(void) return r; } -static int qemu_vmstop_requested(void) +static RunState qemu_vmstop_requested(void) { - int r = vmstop_requested; - vmstop_requested = 0; - return r; + RunState s = vmstop_requested; + vmstop_requested = RSTATE_NO_STATE; + return s; } void qemu_register_reset(QEMUResetHandler *func, void *opaque) @@ -1317,9 +1317,9 @@ void qemu_system_debug_request(void) qemu_notify_event(); } -void qemu_system_vmstop_request(int reason) +void qemu_system_vmstop_request(RunState state) { - vmstop_requested = reason; + vmstop_requested = state; qemu_notify_event(); } @@ -1469,13 +1469,13 @@ static void main_loop(void) #endif if (qemu_debug_requested()) { - vm_stop(VMSTOP_DEBUG); + vm_stop(RSTATE_DEBUG); } if (qemu_shutdown_requested()) { qemu_kill_report(); monitor_protocol_event(QEVENT_SHUTDOWN, NULL); if (no_shutdown) { - vm_stop(VMSTOP_SHUTDOWN); + vm_stop(RSTATE_SHUTDOWN); } else break; } -- cgit 1.4.1 From f5bbfba1ebe8c877ebfe846fc1e73e90da423884 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 29 Jul 2011 15:04:45 -0300 Subject: RunState: Add additional states Currently, only vm_start() and vm_stop() change the VM state. That's, the state is only changed when starting or stopping the VM. This commit adds the runstate_set() function, which makes it possible to also do state transitions when the VM is stopped or running. Additional states are also added and the current state is stored. Signed-off-by: Luiz Capitulino --- cpus.c | 1 + migration.c | 8 +++++++- sysemu.h | 8 +++++++- vl.c | 20 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) (limited to 'vl.c') diff --git a/cpus.c b/cpus.c index 76a79ac7d4..3444bc06e7 100644 --- a/cpus.c +++ b/cpus.c @@ -124,6 +124,7 @@ static void do_vm_stop(RunState state) cpu_disable_ticks(); vm_running = 0; pause_all_vcpus(); + runstate_set(state); vm_state_notify(0, state); qemu_aio_flush(); bdrv_flush_all(); diff --git a/migration.c b/migration.c index 29f1a76df1..f2499cfdd4 100644 --- a/migration.c +++ b/migration.c @@ -72,8 +72,11 @@ void process_incoming_migration(QEMUFile *f) incoming_expected = false; - if (autostart) + if (autostart) { vm_start(); + } else { + runstate_set(RSTATE_PRE_LAUNCH); + } } int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) @@ -390,6 +393,9 @@ void migrate_fd_put_ready(void *opaque) } state = MIG_STATE_ERROR; } + if (state == MIG_STATE_COMPLETED) { + runstate_set(RSTATE_POST_MIGRATE); + } s->state = state; notifier_list_notify(&migration_state_notifiers, NULL); } diff --git a/sysemu.h b/sysemu.h index be3448b155..19088aa2dd 100644 --- a/sysemu.h +++ b/sysemu.h @@ -13,15 +13,19 @@ typedef enum { RSTATE_NO_STATE, RSTATE_DEBUG, /* qemu is running under gdb */ + RSTATE_IN_MIGRATE, /* paused waiting for an incoming migration */ RSTATE_PANICKED, /* paused due to an internal error */ RSTATE_IO_ERROR, /* paused due to an I/O error */ RSTATE_PAUSED, /* paused by the user (ie. the 'stop' command) */ + RSTATE_POST_MIGRATE, /* paused following a successful migration */ + RSTATE_PRE_LAUNCH, /* qemu was started with -S and haven't started */ RSTATE_PRE_MIGRATE, /* paused preparing to finish migrate */ RSTATE_RESTORE, /* paused restoring the VM state */ RSTATE_RUNNING, /* qemu is running */ RSTATE_SAVEVM, /* paused saving VM state */ RSTATE_SHUTDOWN, /* guest shut down and -no-shutdown is in use */ - RSTATE_WATCHDOG /* watchdog fired and qemu is configured to pause */ + RSTATE_WATCHDOG, /* watchdog fired and qemu is configured to pause */ + RSTATE_MAX } RunState; extern const char *bios_name; @@ -32,6 +36,8 @@ extern uint8_t qemu_uuid[]; int qemu_uuid_parse(const char *str, uint8_t *uuid); #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +bool runstate_check(RunState state); +void runstate_set(RunState new_state); typedef struct vm_change_state_entry VMChangeStateEntry; typedef void VMChangeStateHandler(void *opaque, int running, RunState state); diff --git a/vl.c b/vl.c index 304a499551..059e727cb2 100644 --- a/vl.c +++ b/vl.c @@ -322,6 +322,22 @@ static int default_driver_check(QemuOpts *opts, void *opaque) return 0; } +/***********************************************************/ +/* QEMU state */ + +static RunState current_run_state = RSTATE_NO_STATE; + +bool runstate_check(RunState state) +{ + return current_run_state == state; +} + +void runstate_set(RunState new_state) +{ + assert(new_state < RSTATE_MAX); + current_run_state = new_state; +} + /***********************************************************/ /* real time host monotonic timer */ @@ -1161,6 +1177,7 @@ void vm_start(void) if (!vm_running) { cpu_enable_ticks(); vm_running = 1; + runstate_set(RSTATE_RUNNING); vm_state_notify(1, RSTATE_RUNNING); resume_all_vcpus(); monitor_protocol_event(QEVENT_RESUME, NULL); @@ -3438,6 +3455,7 @@ int main(int argc, char **argv, char **envp) } if (incoming) { + runstate_set(RSTATE_IN_MIGRATE); int ret = qemu_start_incoming_migration(incoming); if (ret < 0) { fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", @@ -3446,6 +3464,8 @@ int main(int argc, char **argv, char **envp) } } else if (autostart) { vm_start(); + } else { + runstate_set(RSTATE_PRE_LAUNCH); } os_setup_post(); -- cgit 1.4.1 From 5db9d4d18612bd5852bf663a40cf7bcf1ddc1b03 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 5 Sep 2011 16:36:31 -0300 Subject: runstate_set(): Check for valid transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit could have been folded with the previous one, however doing it separately will allow for easy bisect and revert if needed. Checking and testing all valid transitions wasn't trivial, chances are this will need broader testing to become more stable. This is a transition table as suggested by LluĂ­s Vilanova. Signed-off-by: Luiz Capitulino --- sysemu.h | 1 + vl.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) (limited to 'vl.c') diff --git a/sysemu.h b/sysemu.h index 19088aa2dd..a01ddac564 100644 --- a/sysemu.h +++ b/sysemu.h @@ -36,6 +36,7 @@ extern uint8_t qemu_uuid[]; int qemu_uuid_parse(const char *str, uint8_t *uuid); #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +void runstate_init(void); bool runstate_check(RunState state); void runstate_set(RunState new_state); typedef struct vm_change_state_entry VMChangeStateEntry; diff --git a/vl.c b/vl.c index 059e727cb2..cc68fb327d 100644 --- a/vl.c +++ b/vl.c @@ -327,14 +327,84 @@ static int default_driver_check(QemuOpts *opts, void *opaque) static RunState current_run_state = RSTATE_NO_STATE; +typedef struct { + RunState from; + RunState to; +} RunStateTransition; + +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 }, + + { RSTATE_IN_MIGRATE, RSTATE_RUNNING }, + { RSTATE_IN_MIGRATE, RSTATE_PRE_LAUNCH }, + + { RSTATE_PANICKED, RSTATE_PAUSED }, + + { RSTATE_IO_ERROR, RSTATE_RUNNING }, + + { RSTATE_PAUSED, RSTATE_RUNNING }, + + { RSTATE_POST_MIGRATE, RSTATE_RUNNING }, + + { RSTATE_PRE_LAUNCH, RSTATE_RUNNING }, + { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE }, + + { RSTATE_PRE_MIGRATE, RSTATE_RUNNING }, + { RSTATE_PRE_MIGRATE, RSTATE_POST_MIGRATE }, + + { RSTATE_RESTORE, RSTATE_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 }, + + { RSTATE_SAVEVM, RSTATE_RUNNING }, + + { RSTATE_SHUTDOWN, RSTATE_PAUSED }, + + { RSTATE_WATCHDOG, RSTATE_RUNNING }, + + { RSTATE_MAX, RSTATE_MAX }, +}; + +static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_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 != RSTATE_MAX; p++) { + runstate_valid_transitions[p->from][p->to] = true; + } +} + +/* This function will abort() on invalid state transitions */ void runstate_set(RunState new_state) { - assert(new_state < RSTATE_MAX); + if (new_state >= RSTATE_MAX || + !runstate_valid_transitions[current_run_state][new_state]) { + fprintf(stderr, "invalid runstate transition\n"); + abort(); + } + current_run_state = new_state; } @@ -2219,6 +2289,8 @@ int main(int argc, char **argv, char **envp) g_mem_set_vtable(&mem_trace); g_thread_init(NULL); + runstate_init(); + init_clocks(); qemu_cache_utils_init(envp); -- cgit 1.4.1 From 1bcef683bf840a928d633755031ac572d5fdb851 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 29 Jul 2011 15:15:00 -0300 Subject: Drop the incoming_expected global variable Test against RSTATE_IN_MIGRATE instead. Please, note that the RSTATE_IN_MIGRATE state is only set when all the initial VM setup is done, while 'incoming_expected' was set right in the beginning when parsing command-line options. Shouldn't be a problem as far as I could check. Signed-off-by: Luiz Capitulino --- migration.c | 2 -- monitor.c | 2 +- vl.c | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'vl.c') diff --git a/migration.c b/migration.c index f2499cfdd4..a63e2a21af 100644 --- a/migration.c +++ b/migration.c @@ -70,8 +70,6 @@ void process_incoming_migration(QEMUFile *f) qemu_announce_self(); DPRINTF("successfully loaded vm state\n"); - incoming_expected = false; - if (autostart) { vm_start(); } else { diff --git a/monitor.c b/monitor.c index b98b8bd2b2..68956a5671 100644 --- a/monitor.c +++ b/monitor.c @@ -1311,7 +1311,7 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data) { struct bdrv_iterate_context context = { mon, 0 }; - if (incoming_expected) { + if (runstate_check(RSTATE_IN_MIGRATE)) { qerror_report(QERR_MIGRATION_EXPECTED); return -1; } diff --git a/vl.c b/vl.c index cc68fb327d..2fb09f5012 100644 --- a/vl.c +++ b/vl.c @@ -187,7 +187,6 @@ 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; @@ -3041,7 +3040,6 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_incoming: incoming = optarg; - incoming_expected = true; break; case QEMU_OPTION_nodefaults: default_serial = 0; -- cgit 1.4.1 From 1354869c380cf4560fa3f0520e914cb5ee380ac8 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 29 Jul 2011 15:36:43 -0300 Subject: Drop the vm_running global variable Use runstate_is_running() instead, which is introduced by this commit. Signed-off-by: Luiz Capitulino --- cpus.c | 9 ++++----- gdbstub.c | 4 ++-- hw/etraxfs_dma.c | 2 +- hw/kvmclock.c | 2 +- hw/virtio.c | 2 +- migration.c | 2 +- monitor.c | 4 ++-- qemu-timer.c | 6 +++--- savevm.c | 4 ++-- sysemu.h | 2 +- target-i386/kvm.c | 2 +- ui/sdl.c | 6 +++--- vl.c | 9 ++++++--- xen-all.c | 2 +- 14 files changed, 29 insertions(+), 27 deletions(-) (limited to 'vl.c') diff --git a/cpus.c b/cpus.c index 3444bc06e7..883c27ac9a 100644 --- a/cpus.c +++ b/cpus.c @@ -115,14 +115,13 @@ void cpu_synchronize_all_post_init(void) int cpu_is_stopped(CPUState *env) { - return !vm_running || env->stopped; + return !runstate_is_running() || env->stopped; } static void do_vm_stop(RunState state) { - if (vm_running) { + if (runstate_is_running()) { cpu_disable_ticks(); - vm_running = 0; pause_all_vcpus(); runstate_set(state); vm_state_notify(0, state); @@ -137,7 +136,7 @@ static int cpu_can_run(CPUState *env) if (env->stop) { return 0; } - if (env->stopped || !vm_running) { + if (env->stopped || !runstate_is_running()) { return 0; } return 1; @@ -148,7 +147,7 @@ static bool cpu_thread_is_idle(CPUState *env) if (env->stop || env->queued_work_first) { return false; } - if (env->stopped || !vm_running) { + if (env->stopped || !runstate_is_running()) { return true; } if (!env->halted || qemu_cpu_has_work(env) || diff --git a/gdbstub.c b/gdbstub.c index 75b52e2c2d..12dd100af4 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2534,7 +2534,7 @@ static void gdb_read_byte(GDBState *s, int ch) if (ch != '$') return; } - if (vm_running) { + if (runstate_is_running()) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(RSTATE_PAUSED); @@ -2839,7 +2839,7 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) #ifndef _WIN32 static void gdb_sigterm_handler(int signal) { - if (vm_running) { + if (runstate_is_running()) { vm_stop(RSTATE_PAUSED); } } diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index e8ad9e6a0b..d3082acc8f 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -732,7 +732,7 @@ static void DMA_run(void *opaque) struct fs_dma_ctrl *etraxfs_dmac = opaque; int p = 1; - if (vm_running) + if (runstate_is_running()) p = etraxfs_dmac_run(etraxfs_dmac); if (p) diff --git a/hw/kvmclock.c b/hw/kvmclock.c index 88961be42b..5388bc489d 100644 --- a/hw/kvmclock.c +++ b/hw/kvmclock.c @@ -46,7 +46,7 @@ static void kvmclock_pre_save(void *opaque) * it on next vmsave (which would return a different value). Will be reset * when the VM is continued. */ - s->clock_valid = !vm_running; + s->clock_valid = !runstate_is_running(); } static int kvmclock_post_load(void *opaque, int version_id) diff --git a/hw/virtio.c b/hw/virtio.c index 74ab79e6b5..c577bbe483 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -870,7 +870,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, vdev->queue_sel = 0; vdev->config_vector = VIRTIO_NO_VECTOR; vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); - vdev->vm_running = vm_running; + vdev->vm_running = runstate_is_running(); for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; diff --git a/migration.c b/migration.c index a63e2a21af..7dd8f4eee9 100644 --- a/migration.c +++ b/migration.c @@ -372,7 +372,7 @@ void migrate_fd_put_ready(void *opaque) DPRINTF("iterate\n"); if (qemu_savevm_state_iterate(s->mon, s->file) == 1) { int state; - int old_vm_running = vm_running; + int old_vm_running = runstate_is_running(); DPRINTF("done iterating\n"); vm_stop(RSTATE_PRE_MIGRATE); diff --git a/monitor.c b/monitor.c index 68956a5671..442b4cf01d 100644 --- a/monitor.c +++ b/monitor.c @@ -2632,7 +2632,7 @@ static void do_info_status_print(Monitor *mon, const QObject *data) static void do_info_status(Monitor *mon, QObject **ret_data) { *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }", - vm_running, singlestep); + runstate_is_running(), singlestep); } static qemu_acl *find_acl(Monitor *mon, const char *name) @@ -2825,7 +2825,7 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) static void do_loadvm(Monitor *mon, const QDict *qdict) { - int saved_vm_running = vm_running; + int saved_vm_running = runstate_is_running(); const char *name = qdict_get_str(qdict, "name"); vm_stop(RSTATE_RESTORE); diff --git a/qemu-timer.c b/qemu-timer.c index b5827862d9..ad1fc8b871 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -230,7 +230,7 @@ static void icount_adjust(void) int64_t delta; static int64_t last_delta; /* If the VM is not running, then do nothing. */ - if (!vm_running) + if (!runstate_is_running()) return; cur_time = cpu_get_clock(); @@ -388,7 +388,7 @@ static void icount_warp_rt(void *opaque) return; } - if (vm_running) { + if (runstate_is_running()) { int64_t clock = qemu_get_clock_ns(rt_clock); int64_t warp_delta = clock - vm_clock_warp_start; if (use_icount == 1) { @@ -710,7 +710,7 @@ void qemu_run_all_timers(void) } /* vm time timers */ - if (vm_running) { + if (runstate_is_running()) { qemu_run_timers(vm_clock); } diff --git a/savevm.c b/savevm.c index f1f7735d11..46f2447dc0 100644 --- a/savevm.c +++ b/savevm.c @@ -1602,7 +1602,7 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f) int saved_vm_running; int ret; - saved_vm_running = vm_running; + saved_vm_running = runstate_is_running(); vm_stop(RSTATE_SAVEVM); if (qemu_savevm_state_blocked(mon)) { @@ -1931,7 +1931,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) return; } - saved_vm_running = vm_running; + saved_vm_running = runstate_is_running(); vm_stop(RSTATE_SAVEVM); memset(sn, 0, sizeof(*sn)); diff --git a/sysemu.h b/sysemu.h index a01ddac564..9a2c531465 100644 --- a/sysemu.h +++ b/sysemu.h @@ -30,7 +30,6 @@ typedef enum { extern const char *bios_name; -extern int vm_running; extern const char *qemu_name; extern uint8_t qemu_uuid[]; int qemu_uuid_parse(const char *str, uint8_t *uuid); @@ -39,6 +38,7 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid); void runstate_init(void); bool runstate_check(RunState state); void runstate_set(RunState new_state); +int runstate_is_running(void); typedef struct vm_change_state_entry VMChangeStateEntry; typedef void VMChangeStateHandler(void *opaque, int running, RunState state); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ead34ea38d..b6eef047bf 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1130,7 +1130,7 @@ static int kvm_get_msrs(CPUState *env) if (!env->tsc_valid) { msrs[n++].index = MSR_IA32_TSC; - env->tsc_valid = !vm_running; + env->tsc_valid = !runstate_is_running(); } #ifdef TARGET_X86_64 diff --git a/ui/sdl.c b/ui/sdl.c index c7aaedf32d..8cafc44e71 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -409,7 +409,7 @@ static void sdl_update_caption(void) char icon_title[1024]; const char *status = ""; - if (!vm_running) + if (!runstate_is_running()) status = " [Stopped]"; else if (gui_grab) { if (alt_grab) @@ -853,8 +853,8 @@ static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; - if (last_vm_running != vm_running) { - last_vm_running = vm_running; + if (last_vm_running != runstate_is_running()) { + last_vm_running = runstate_is_running(); sdl_update_caption(); } diff --git a/vl.c b/vl.c index 2fb09f5012..9128d48fea 100644 --- a/vl.c +++ b/vl.c @@ -185,7 +185,6 @@ int mem_prealloc = 0; /* force preallocation of physical target memory */ #endif int nb_nics; NICInfo nd_table[MAX_NICS]; -int vm_running; int autostart; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ @@ -407,6 +406,11 @@ void runstate_set(RunState new_state) current_run_state = new_state; } +int runstate_is_running(void) +{ + return runstate_check(RSTATE_RUNNING); +} + /***********************************************************/ /* real time host monotonic timer */ @@ -1243,9 +1247,8 @@ void vm_state_notify(int running, RunState state) void vm_start(void) { - if (!vm_running) { + if (!runstate_is_running()) { cpu_enable_ticks(); - vm_running = 1; runstate_set(RSTATE_RUNNING); vm_state_notify(1, RSTATE_RUNNING); resume_all_vcpus(); diff --git a/xen-all.c b/xen-all.c index b119817f30..b5e28abd40 100644 --- a/xen-all.c +++ b/xen-all.c @@ -736,7 +736,7 @@ static void cpu_handle_ioreq(void *opaque) * guest resumes and does a hlt with interrupts disabled which * causes Xen to powerdown the domain. */ - if (vm_running) { + if (runstate_is_running()) { if (qemu_shutdown_requested_get()) { destroy_hvm_domain(); } -- cgit 1.4.1 From 6667b23f300ff08a47a73821ce2fb7f773754969 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 29 Jul 2011 15:57:54 -0300 Subject: Monitor/QMP: Don't allow cont on bad VM state We have two states where issuing cont before system_reset can cause problems: RSTATE_SHUTDOWN (when -no-shutdown is used) and RSTATE_PANICKED (which only happens with kvm). This commit fixes that by doing the following when state is RSTATE_SHUTDOWN or RSTATE_PANICKED: 1. returning an error to the user/client if cont is issued 2. automatically transition to RSTATE_PAUSED during system_reset Signed-off-by: Luiz Capitulino --- monitor.c | 5 +++++ qerror.c | 4 ++++ qerror.h | 3 +++ vl.c | 4 ++++ 4 files changed, 16 insertions(+) (limited to 'vl.c') diff --git a/monitor.c b/monitor.c index 442b4cf01d..ac68edf98b 100644 --- a/monitor.c +++ b/monitor.c @@ -1314,7 +1314,12 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data) if (runstate_check(RSTATE_IN_MIGRATE)) { qerror_report(QERR_MIGRATION_EXPECTED); return -1; + } else if (runstate_check(RSTATE_PANICKED) || + runstate_check(RSTATE_SHUTDOWN)) { + qerror_report(QERR_RESET_REQUIRED); + return -1; } + bdrv_iterate(encrypted_bdrv_it, &context); /* only resume the vm if all keys are set and valid */ if (!context.err) { diff --git a/qerror.c b/qerror.c index 3d64b80b24..c591a5443c 100644 --- a/qerror.c +++ b/qerror.c @@ -193,6 +193,10 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_QMP_EXTRA_MEMBER, .desc = "QMP input object member '%(member)' is unexpected", }, + { + .error_fmt = QERR_RESET_REQUIRED, + .desc = "Resetting the Virtual Machine is required", + }, { .error_fmt = QERR_SET_PASSWD_FAILED, .desc = "Could not set password", diff --git a/qerror.h b/qerror.h index 8058456d2e..d4070015f7 100644 --- a/qerror.h +++ b/qerror.h @@ -163,6 +163,9 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_QMP_EXTRA_MEMBER \ "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" +#define QERR_RESET_REQUIRED \ + "{ 'class': 'ResetRequired', 'data': {} }" + #define QERR_SET_PASSWD_FAILED \ "{ 'class': 'SetPasswdFailed', 'data': {} }" diff --git a/vl.c b/vl.c index 9128d48fea..686e491e9a 100644 --- a/vl.c +++ b/vl.c @@ -1573,6 +1573,10 @@ static void main_loop(void) 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); -- cgit 1.4.1 From 9e37b9dc5bf037453e062ee515014875cd05068d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 29 Aug 2011 16:02:57 -0300 Subject: QMP: query-status: Introduce 'status' key This new key reports the current VM status to clients. Please, check the documentation being added in this commit for more details. Signed-off-by: Luiz Capitulino --- monitor.c | 3 +-- qmp-commands.hx | 19 ++++++++++++++++++- sysemu.h | 1 + vl.c | 23 +++++++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) (limited to 'vl.c') diff --git a/monitor.c b/monitor.c index ac68edf98b..ab71d2d9e5 100644 --- a/monitor.c +++ b/monitor.c @@ -2636,8 +2636,7 @@ static void do_info_status_print(Monitor *mon, const QObject *data) static void do_info_status(Monitor *mon, QObject **ret_data) { - *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }", - runstate_is_running(), singlestep); + *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i, 'status': %s }", runstate_is_running(), singlestep, runstate_as_string()); } static qemu_acl *find_acl(Monitor *mon, const char *name) diff --git a/qmp-commands.hx b/qmp-commands.hx index d1c2c5905d..d83bce5662 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1573,11 +1573,28 @@ Return a json-object with the following information: - "running": true if the VM is running, or false if it is paused (json-bool) - "singlestep": true if the VM is in single step mode, false otherwise (json-bool) +- "status": one of the following values (json-string) + "debug" - QEMU is running on a debugger + "inmigrate" - guest is paused waiting for an incoming migration + "internal-error" - An internal error that prevents further guest + execution has occurred + "io-error" - the last IOP has failed and the device is configured + to pause on I/O errors + "paused" - guest has been paused via the 'stop' command + "postmigrate" - guest is paused following a successful 'migrate' + "prelaunch" - QEMU was started with -S and guest has not started + "finish-migrate" - guest is paused to finish the migration process + "restore-vm" - guest is paused to restore VM state + "running" - guest is actively running + "save-vm" - guest is paused to save the VM state + "shutdown" - guest is shut down (and -no-shutdown is in use) + "watchdog" - the watchdog action is configured to pause and + has been triggered Example: -> { "execute": "query-status" } -<- { "return": { "running": true, "singlestep": false } } +<- { "return": { "running": true, "singlestep": false, "status": "running" } } EQMP diff --git a/sysemu.h b/sysemu.h index 9a2c531465..43ff546f9b 100644 --- a/sysemu.h +++ b/sysemu.h @@ -39,6 +39,7 @@ void runstate_init(void); bool runstate_check(RunState state); void runstate_set(RunState new_state); int runstate_is_running(void); +const char *runstate_as_string(void); typedef struct vm_change_state_entry VMChangeStateEntry; typedef void VMChangeStateHandler(void *opaque, int running, RunState state); diff --git a/vl.c b/vl.c index 686e491e9a..08591c397b 100644 --- a/vl.c +++ b/vl.c @@ -378,6 +378,22 @@ static const RunStateTransition runstate_transitions_def[] = { 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", +}; + bool runstate_check(RunState state) { return current_run_state == state; @@ -406,6 +422,13 @@ void runstate_set(RunState new_state) current_run_state = new_state; } +const char *runstate_as_string(void) +{ + assert(current_run_state > RSTATE_NO_STATE && + current_run_state < RSTATE_MAX); + return runstate_name_tbl[current_run_state]; +} + int runstate_is_running(void) { return runstate_check(RSTATE_RUNNING); -- cgit 1.4.1