#include "qemu-thread.h"
#include "cpus.h"
+#include "qtest.h"
#include "main-loop.h"
+#include "bitmap.h"
#ifndef _WIN32
#include "compatfd.h"
static CPUArchState *next_cpu;
+static bool cpu_thread_is_idle(CPUArchState *env)
+{
+ if (env->stop || env->queued_work_first) {
+ return false;
+ }
+ if (env->stopped || !runstate_is_running()) {
+ return true;
+ }
+ if (!env->halted || qemu_cpu_has_work(env) ||
+ kvm_async_interrupts_enabled()) {
+ return false;
+ }
+ return true;
+}
+
+static bool all_cpu_threads_idle(void)
+{
+ CPUArchState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ if (!cpu_thread_is_idle(env)) {
+ return false;
+ }
+ }
+ return true;
+}
+
/***********************************************************/
/* guest cycle counter */
vm_clock_warp_start = -1;
}
+void qtest_clock_warp(int64_t dest)
+{
+ int64_t clock = qemu_get_clock_ns(vm_clock);
+ assert(qtest_enabled());
+ while (clock < dest) {
+ int64_t deadline = qemu_clock_deadline(vm_clock);
+ int64_t warp = MIN(dest - clock, deadline);
+ qemu_icount_bias += warp;
+ qemu_run_timers(vm_clock);
+ clock = qemu_get_clock_ns(vm_clock);
+ }
+ qemu_notify_event();
+}
+
void qemu_clock_warp(QEMUClock *clock)
{
int64_t deadline;
return;
}
+ if (qtest_enabled()) {
+ /* When testing, qtest commands advance icount. */
+ return;
+ }
+
vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
deadline = qemu_clock_deadline(vm_clock);
if (deadline > 0) {
fprintf(stderr, "\n");
for(env = first_cpu; env != NULL; env = env->next_cpu) {
fprintf(stderr, "CPU #%d:\n", env->cpu_index);
-#ifdef TARGET_I386
- cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
-#else
- cpu_dump_state(env, stderr, fprintf, 0);
-#endif
+ cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU);
}
va_end(ap);
abort();
return 1;
}
-static bool cpu_thread_is_idle(CPUArchState *env)
-{
- if (env->stop || env->queued_work_first) {
- return false;
- }
- if (env->stopped || !runstate_is_running()) {
- return true;
- }
- if (!env->halted || qemu_cpu_has_work(env) ||
- (kvm_enabled() && kvm_irqchip_in_kernel())) {
- return false;
- }
- return true;
-}
-
-bool all_cpu_threads_idle(void)
-{
- CPUArchState *env;
-
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- if (!cpu_thread_is_idle(env)) {
- return false;
- }
- }
- return true;
-}
-
static void cpu_handle_guest_debug(CPUArchState *env)
{
gdb_set_stop_cpu(env);
}
#endif /* _WIN32 */
-QemuMutex qemu_global_mutex;
+static QemuMutex qemu_global_mutex;
static QemuCond qemu_io_proceeded_cond;
static bool iothread_requesting_mutex;
static void qemu_wait_io_event_common(CPUArchState *env)
{
+ CPUState *cpu = ENV_GET_CPU(env);
+
if (env->stop) {
env->stop = 0;
env->stopped = 1;
qemu_cond_signal(&qemu_pause_cond);
}
flush_queued_work(env);
- env->thread_kicked = false;
+ cpu->thread_kicked = false;
}
static void qemu_tcg_wait_io_event(void)
static void *qemu_kvm_cpu_thread_fn(void *arg)
{
CPUArchState *env = arg;
+ CPUState *cpu = ENV_GET_CPU(env);
int r;
qemu_mutex_lock(&qemu_global_mutex);
- qemu_thread_get_self(env->thread);
+ qemu_thread_get_self(cpu->thread);
env->thread_id = qemu_get_thread_id();
cpu_single_env = env;
return NULL;
}
+static void *qemu_dummy_cpu_thread_fn(void *arg)
+{
+#ifdef _WIN32
+ fprintf(stderr, "qtest is not supported under Windows\n");
+ exit(1);
+#else
+ CPUArchState *env = arg;
+ CPUState *cpu = ENV_GET_CPU(env);
+ sigset_t waitset;
+ int r;
+
+ qemu_mutex_lock_iothread();
+ qemu_thread_get_self(cpu->thread);
+ env->thread_id = qemu_get_thread_id();
+
+ sigemptyset(&waitset);
+ sigaddset(&waitset, SIG_IPI);
+
+ /* signal CPU creation */
+ env->created = 1;
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ cpu_single_env = env;
+ while (1) {
+ cpu_single_env = NULL;
+ qemu_mutex_unlock_iothread();
+ do {
+ int sig;
+ r = sigwait(&waitset, &sig);
+ } while (r == -1 && (errno == EAGAIN || errno == EINTR));
+ if (r == -1) {
+ perror("sigwait");
+ exit(1);
+ }
+ qemu_mutex_lock_iothread();
+ cpu_single_env = env;
+ qemu_wait_io_event_common(env);
+ }
+
+ return NULL;
+#endif
+}
+
static void tcg_exec_all(void);
static void *qemu_tcg_cpu_thread_fn(void *arg)
{
CPUArchState *env = arg;
+ CPUState *cpu = ENV_GET_CPU(env);
qemu_tcg_init_cpu_signals();
- qemu_thread_get_self(env->thread);
+ qemu_thread_get_self(cpu->thread);
/* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
static void qemu_cpu_kick_thread(CPUArchState *env)
{
+ CPUState *cpu = ENV_GET_CPU(env);
#ifndef _WIN32
int err;
- err = pthread_kill(env->thread->thread, SIG_IPI);
+ err = pthread_kill(cpu->thread->thread, SIG_IPI);
if (err) {
fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
exit(1);
}
#else /* _WIN32 */
if (!qemu_cpu_is_self(env)) {
- SuspendThread(env->hThread);
+ SuspendThread(cpu->hThread);
cpu_signal(0);
- ResumeThread(env->hThread);
+ ResumeThread(cpu->hThread);
}
#endif
}
void qemu_cpu_kick(void *_env)
{
CPUArchState *env = _env;
+ CPUState *cpu = ENV_GET_CPU(env);
qemu_cond_broadcast(env->halt_cond);
- if (kvm_enabled() && !env->thread_kicked) {
+ if (!tcg_enabled() && !cpu->thread_kicked) {
qemu_cpu_kick_thread(env);
- env->thread_kicked = true;
+ cpu->thread_kicked = true;
}
}
{
#ifndef _WIN32
assert(cpu_single_env);
+ CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
- if (!cpu_single_env->thread_kicked) {
+ if (!cpu_single_cpu->thread_kicked) {
qemu_cpu_kick_thread(cpu_single_env);
- cpu_single_env->thread_kicked = true;
+ cpu_single_cpu->thread_kicked = true;
}
#else
abort();
int qemu_cpu_is_self(void *_env)
{
CPUArchState *env = _env;
+ CPUState *cpu = ENV_GET_CPU(env);
+
+ return qemu_thread_is_self(cpu->thread);
+}
- return qemu_thread_is_self(env->thread);
+static bool qemu_in_vcpu_thread(void)
+{
+ return cpu_single_env && qemu_cpu_is_self(cpu_single_env);
}
void qemu_mutex_lock_iothread(void)
{
- if (kvm_enabled()) {
+ if (!tcg_enabled()) {
qemu_mutex_lock(&qemu_global_mutex);
} else {
iothread_requesting_mutex = true;
penv = penv->next_cpu;
}
- if (!qemu_thread_is_self(&io_thread)) {
+ if (qemu_in_vcpu_thread()) {
cpu_stop_current();
if (!kvm_enabled()) {
while (penv) {
static void qemu_tcg_init_vcpu(void *_env)
{
CPUArchState *env = _env;
+ CPUState *cpu = ENV_GET_CPU(env);
/* share a single thread for all cpus with TCG */
if (!tcg_cpu_thread) {
- env->thread = g_malloc0(sizeof(QemuThread));
+ cpu->thread = g_malloc0(sizeof(QemuThread));
env->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(env->halt_cond);
tcg_halt_cond = env->halt_cond;
- qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env,
+ qemu_thread_create(cpu->thread, qemu_tcg_cpu_thread_fn, env,
QEMU_THREAD_JOINABLE);
#ifdef _WIN32
- env->hThread = qemu_thread_get_handle(env->thread);
+ cpu->hThread = qemu_thread_get_handle(cpu->thread);
#endif
while (env->created == 0) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
- tcg_cpu_thread = env->thread;
+ tcg_cpu_thread = cpu->thread;
} else {
- env->thread = tcg_cpu_thread;
+ cpu->thread = tcg_cpu_thread;
env->halt_cond = tcg_halt_cond;
}
}
static void qemu_kvm_start_vcpu(CPUArchState *env)
{
- env->thread = g_malloc0(sizeof(QemuThread));
+ CPUState *cpu = ENV_GET_CPU(env);
+
+ cpu->thread = g_malloc0(sizeof(QemuThread));
env->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(env->halt_cond);
- qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env,
+ qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, env,
+ QEMU_THREAD_JOINABLE);
+ while (env->created == 0) {
+ qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+ }
+}
+
+static void qemu_dummy_start_vcpu(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+
+ cpu->thread = g_malloc0(sizeof(QemuThread));
+ env->halt_cond = g_malloc0(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, env,
QEMU_THREAD_JOINABLE);
while (env->created == 0) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
env->stopped = 1;
if (kvm_enabled()) {
qemu_kvm_start_vcpu(env);
- } else {
+ } else if (tcg_enabled()) {
qemu_tcg_init_vcpu(env);
+ } else {
+ qemu_dummy_start_vcpu(env);
}
}
void vm_stop(RunState state)
{
- if (!qemu_thread_is_self(&io_thread)) {
+ if (qemu_in_vcpu_thread()) {
qemu_system_vmstop_request(state);
/*
* FIXME: should not return to device code in case
for (env = first_cpu; env != NULL; env = env->next_cpu) {
for (i = 0; i < nb_numa_nodes; i++) {
- if (node_cpumask[i] & (1 << env->cpu_index)) {
+ if (test_bit(env->cpu_index, node_cpumask[i])) {
env->numa_node = i;
}
}
void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
{
/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list_id)
- cpu_list_id(f, cpu_fprintf, optarg);
-#elif defined(cpu_list)
- cpu_list(f, cpu_fprintf); /* deprecated */
+#if defined(cpu_list)
+ cpu_list(f, cpu_fprintf);
#endif
}