#endif /* CONFIG_LINUX */
-static QemuMutex qemu_global_mutex;
+/* The Big QEMU Lock (BQL) */
+static QemuMutex bql;
/*
* The chosen accelerator is supposed to register this.
return true;
}
+void cpu_exec_reset_hold(CPUState *cpu)
+{
+ if (cpus_accel->cpu_reset_hold) {
+ cpus_accel->cpu_reset_hold(cpu);
+ }
+}
+
int64_t cpus_get_virtual_clock(void)
{
/*
}
}
+/*
+ * True if the vm was previously suspended, and has not been woken or reset.
+ */
+static int vm_was_suspended;
+
+void vm_set_suspended(bool suspended)
+{
+ vm_was_suspended = suspended;
+}
+
+bool vm_get_suspended(void)
+{
+ return vm_was_suspended;
+}
+
static int do_vm_stop(RunState state, bool send_stop)
{
int ret = 0;
+ RunState oldstate = runstate_get();
- if (runstate_is_running()) {
+ if (runstate_is_live(oldstate)) {
+ vm_was_suspended = (oldstate == RUN_STATE_SUSPENDED);
runstate_set(state);
cpu_disable_ticks();
- pause_all_vcpus();
+ if (oldstate == RUN_STATE_RUNNING) {
+ pause_all_vcpus();
+ }
vm_state_notify(0, state);
if (send_stop) {
qapi_event_send_stop();
qemu_init_sigbus();
qemu_cond_init(&qemu_cpu_cond);
qemu_cond_init(&qemu_pause_cond);
- qemu_mutex_init(&qemu_global_mutex);
+ qemu_mutex_init(&bql);
qemu_thread_get_self(&io_thread);
}
void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
{
- do_run_on_cpu(cpu, func, data, &qemu_global_mutex);
+ do_run_on_cpu(cpu, func, data, &bql);
}
static void qemu_cpu_stop(CPUState *cpu, bool exit)
slept = true;
qemu_plugin_vcpu_idle_cb(cpu);
}
- qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
+ qemu_cond_wait(cpu->halt_cond, &bql);
}
if (slept) {
qemu_plugin_vcpu_resume_cb(cpu);
return current_cpu && qemu_cpu_is_self(current_cpu);
}
-QEMU_DEFINE_STATIC_CO_TLS(bool, iothread_locked)
+QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
-bool qemu_mutex_iothread_locked(void)
+bool bql_locked(void)
{
- return get_iothread_locked();
+ return get_bql_locked();
}
bool qemu_in_main_thread(void)
{
- return qemu_mutex_iothread_locked();
+ return bql_locked();
}
/*
* The BQL is taken from so many places that it is worth profiling the
* callers directly, instead of funneling them all through a single function.
*/
-void qemu_mutex_lock_iothread_impl(const char *file, int line)
+void bql_lock_impl(const char *file, int line)
{
- QemuMutexLockFunc bql_lock = qatomic_read(&qemu_bql_mutex_lock_func);
+ QemuMutexLockFunc bql_lock_fn = qatomic_read(&bql_mutex_lock_func);
- g_assert(!qemu_mutex_iothread_locked());
- bql_lock(&qemu_global_mutex, file, line);
- set_iothread_locked(true);
+ g_assert(!bql_locked());
+ bql_lock_fn(&bql, file, line);
+ set_bql_locked(true);
}
-void qemu_mutex_unlock_iothread(void)
+void bql_unlock(void)
{
- g_assert(qemu_mutex_iothread_locked());
- set_iothread_locked(false);
- qemu_mutex_unlock(&qemu_global_mutex);
+ g_assert(bql_locked());
+ set_bql_locked(false);
+ qemu_mutex_unlock(&bql);
}
-void qemu_cond_wait_iothread(QemuCond *cond)
+void qemu_cond_wait_bql(QemuCond *cond)
{
- qemu_cond_wait(cond, &qemu_global_mutex);
+ qemu_cond_wait(cond, &bql);
}
-void qemu_cond_timedwait_iothread(QemuCond *cond, int ms)
+void qemu_cond_timedwait_bql(QemuCond *cond, int ms)
{
- qemu_cond_timedwait(cond, &qemu_global_mutex, ms);
+ qemu_cond_timedwait(cond, &bql, ms);
}
/* signal CPU creation */
replay_mutex_unlock();
while (!all_vcpus_paused()) {
- qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
+ qemu_cond_wait(&qemu_pause_cond, &bql);
CPU_FOREACH(cpu) {
qemu_cpu_kick(cpu);
}
}
- qemu_mutex_unlock_iothread();
+ bql_unlock();
replay_mutex_lock();
- qemu_mutex_lock_iothread();
+ bql_lock();
}
void cpu_resume(CPUState *cpu)
cpu->stop = true;
cpu->unplug = true;
qemu_cpu_kick(cpu);
- qemu_mutex_unlock_iothread();
+ bql_unlock();
qemu_thread_join(cpu->thread);
- qemu_mutex_lock_iothread();
+ bql_lock();
}
void cpus_register_accel(const AccelOpsClass *ops)
{
MachineState *ms = MACHINE(qdev_get_machine());
- cpu->nr_cores = ms->smp.cores;
+ cpu->nr_cores = machine_topo_get_cores_per_socket(ms);
cpu->nr_threads = ms->smp.threads;
cpu->stopped = true;
cpu->random_seed = qemu_guest_random_seed_thread_part1();
cpus_accel->create_vcpu_thread(cpu);
while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+ qemu_cond_wait(&qemu_cpu_cond, &bql);
}
}
/**
* Prepare for (re)starting the VM.
- * Returns -1 if the vCPUs are not to be restarted (e.g. if they are already
- * running or in case of an error condition), 0 otherwise.
+ * Returns 0 if the vCPUs should be restarted, -1 on an error condition,
+ * and 1 otherwise.
*/
int vm_prepare_start(bool step_pending)
{
+ int ret = vm_was_suspended ? 1 : 0;
+ RunState state = vm_was_suspended ? RUN_STATE_SUSPENDED : RUN_STATE_RUNNING;
RunState requested;
qemu_vmstop_requested(&requested);
qapi_event_send_resume();
cpu_enable_ticks();
- runstate_set(RUN_STATE_RUNNING);
- vm_state_notify(1, RUN_STATE_RUNNING);
- return 0;
+ runstate_set(state);
+ vm_state_notify(1, state);
+ vm_was_suspended = false;
+ return ret;
}
void vm_start(void)
}
}
+void vm_resume(RunState state)
+{
+ if (runstate_is_live(state)) {
+ vm_start();
+ } else {
+ runstate_set(state);
+ }
+}
+
/* does a state transition even if the VM is already stopped,
current state is forgotten forever */
int vm_stop_force_state(RunState state)
{
- if (runstate_is_running()) {
+ if (runstate_is_live(runstate_get())) {
return vm_stop(state);
} else {
int ret;