vl: allow other threads to do qemu_system_vmstop_request
There patch protects vmstop_requested with a lock and introduces qemu_system_vmstop_request_prepare. Together with the new call to qemu_vmstop_requested in vm_start, qemu_system_vmstop_request_prepare avoids a race where the VM could remain stopped even though the iostatus of a block device has already been set (for example). qemu_system_vmstop_request_prepare however also lets the caller thread delay observation of the state change until it has itself communicated that change to the user. This delay avoids any possibility of a wrong reordering of the BLOCK_IO_ERROR event and the subsequent STOP event. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
5d5da114b3
commit
74892d2468
1
cpus.c
1
cpus.c
|
@ -1206,6 +1206,7 @@ void cpu_stop_current(void)
|
||||||
int vm_stop(RunState state)
|
int vm_stop(RunState state)
|
||||||
{
|
{
|
||||||
if (qemu_in_vcpu_thread()) {
|
if (qemu_in_vcpu_thread()) {
|
||||||
|
qemu_system_vmstop_request_prepare();
|
||||||
qemu_system_vmstop_request(state);
|
qemu_system_vmstop_request(state);
|
||||||
/*
|
/*
|
||||||
* FIXME: should not return to device code in case
|
* FIXME: should not return to device code in case
|
||||||
|
|
|
@ -62,6 +62,7 @@ void qemu_system_powerdown_request(void);
|
||||||
void qemu_register_powerdown_notifier(Notifier *notifier);
|
void qemu_register_powerdown_notifier(Notifier *notifier);
|
||||||
void qemu_system_debug_request(void);
|
void qemu_system_debug_request(void);
|
||||||
void qemu_system_vmstop_request(RunState reason);
|
void qemu_system_vmstop_request(RunState reason);
|
||||||
|
void qemu_system_vmstop_request_prepare(void);
|
||||||
int qemu_shutdown_requested_get(void);
|
int qemu_shutdown_requested_get(void);
|
||||||
int qemu_reset_requested_get(void);
|
int qemu_reset_requested_get(void);
|
||||||
void qemu_system_killed(int signal, pid_t pid);
|
void qemu_system_killed(int signal, pid_t pid);
|
||||||
|
|
|
@ -42,7 +42,7 @@ void HELPER(ill)(CPULM32State *env)
|
||||||
fprintf(stderr, "VM paused due to illegal instruction. "
|
fprintf(stderr, "VM paused due to illegal instruction. "
|
||||||
"Connect a debugger or switch to the monitor console "
|
"Connect a debugger or switch to the monitor console "
|
||||||
"to find out more.\n");
|
"to find out more.\n");
|
||||||
qemu_system_vmstop_request(RUN_STATE_PAUSED);
|
vm_stop(RUN_STATE_PAUSED);
|
||||||
cs->halted = 1;
|
cs->halted = 1;
|
||||||
raise_exception(env, EXCP_HALTED);
|
raise_exception(env, EXCP_HALTED);
|
||||||
#endif
|
#endif
|
||||||
|
|
85
vl.c
85
vl.c
|
@ -574,6 +574,10 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
|
||||||
|
|
||||||
static RunState current_run_state = RUN_STATE_PRELAUNCH;
|
static RunState current_run_state = RUN_STATE_PRELAUNCH;
|
||||||
|
|
||||||
|
/* We use RUN_STATE_MAX but any invalid value will do */
|
||||||
|
static RunState vmstop_requested = RUN_STATE_MAX;
|
||||||
|
static QemuMutex vmstop_lock;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
RunState from;
|
RunState from;
|
||||||
RunState to;
|
RunState to;
|
||||||
|
@ -650,10 +654,11 @@ static void runstate_init(void)
|
||||||
const RunStateTransition *p;
|
const RunStateTransition *p;
|
||||||
|
|
||||||
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
|
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
|
||||||
|
|
||||||
for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) {
|
for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) {
|
||||||
runstate_valid_transitions[p->from][p->to] = true;
|
runstate_valid_transitions[p->from][p->to] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_mutex_init(&vmstop_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function will abort() on invalid state transitions */
|
/* This function will abort() on invalid state transitions */
|
||||||
|
@ -693,6 +698,54 @@ StatusInfo *qmp_query_status(Error **errp)
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool qemu_vmstop_requested(RunState *r)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&vmstop_lock);
|
||||||
|
*r = vmstop_requested;
|
||||||
|
vmstop_requested = RUN_STATE_MAX;
|
||||||
|
qemu_mutex_unlock(&vmstop_lock);
|
||||||
|
return *r < RUN_STATE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_system_vmstop_request_prepare(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&vmstop_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_system_vmstop_request(RunState state)
|
||||||
|
{
|
||||||
|
vmstop_requested = state;
|
||||||
|
qemu_mutex_unlock(&vmstop_lock);
|
||||||
|
qemu_notify_event();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_start(void)
|
||||||
|
{
|
||||||
|
RunState requested;
|
||||||
|
|
||||||
|
qemu_vmstop_requested(&requested);
|
||||||
|
if (runstate_is_running() && requested == RUN_STATE_MAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that a STOP/RESUME pair of events is emitted if a
|
||||||
|
* vmstop request was pending. The BLOCK_IO_ERROR event, for
|
||||||
|
* example, according to documentation is always followed by
|
||||||
|
* the STOP event.
|
||||||
|
*/
|
||||||
|
if (runstate_is_running()) {
|
||||||
|
monitor_protocol_event(QEVENT_STOP, NULL);
|
||||||
|
} else {
|
||||||
|
cpu_enable_ticks();
|
||||||
|
runstate_set(RUN_STATE_RUNNING);
|
||||||
|
vm_state_notify(1, RUN_STATE_RUNNING);
|
||||||
|
resume_all_vcpus();
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_protocol_event(QEVENT_RESUME, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* real time host monotonic timer */
|
/* real time host monotonic timer */
|
||||||
|
|
||||||
|
@ -1658,17 +1711,6 @@ void vm_state_notify(int running, RunState state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_start(void)
|
|
||||||
{
|
|
||||||
if (!runstate_is_running()) {
|
|
||||||
cpu_enable_ticks();
|
|
||||||
runstate_set(RUN_STATE_RUNNING);
|
|
||||||
vm_state_notify(1, RUN_STATE_RUNNING);
|
|
||||||
resume_all_vcpus();
|
|
||||||
monitor_protocol_event(QEVENT_RESUME, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset/shutdown handler */
|
/* reset/shutdown handler */
|
||||||
|
|
||||||
typedef struct QEMUResetEntry {
|
typedef struct QEMUResetEntry {
|
||||||
|
@ -1693,7 +1735,6 @@ static NotifierList suspend_notifiers =
|
||||||
static NotifierList wakeup_notifiers =
|
static NotifierList wakeup_notifiers =
|
||||||
NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
|
NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
|
||||||
static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
|
static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
|
||||||
static RunState vmstop_requested = RUN_STATE_MAX;
|
|
||||||
|
|
||||||
int qemu_shutdown_requested_get(void)
|
int qemu_shutdown_requested_get(void)
|
||||||
{
|
{
|
||||||
|
@ -1761,18 +1802,6 @@ static int qemu_debug_requested(void)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We use RUN_STATE_MAX but any invalid value will do */
|
|
||||||
static bool qemu_vmstop_requested(RunState *r)
|
|
||||||
{
|
|
||||||
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)
|
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
|
||||||
{
|
{
|
||||||
QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry));
|
QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry));
|
||||||
|
@ -1922,12 +1951,6 @@ void qemu_system_debug_request(void)
|
||||||
qemu_notify_event();
|
qemu_notify_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_system_vmstop_request(RunState state)
|
|
||||||
{
|
|
||||||
vmstop_requested = state;
|
|
||||||
qemu_notify_event();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool main_loop_should_exit(void)
|
static bool main_loop_should_exit(void)
|
||||||
{
|
{
|
||||||
RunState r;
|
RunState r;
|
||||||
|
|
Loading…
Reference in New Issue