|
|
|
@ -130,10 +130,12 @@ static void do_vm_stop(int reason) |
|
|
|
|
|
|
|
static int cpu_can_run(CPUState *env) |
|
|
|
{ |
|
|
|
if (env->stop) |
|
|
|
if (env->stop) { |
|
|
|
return 0; |
|
|
|
if (env->stopped || !vm_running) |
|
|
|
} |
|
|
|
if (env->stopped || !vm_running) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
@ -225,9 +227,9 @@ static void qemu_event_increment(void) |
|
|
|
static const uint64_t val = 1; |
|
|
|
ssize_t ret; |
|
|
|
|
|
|
|
if (io_thread_fd == -1) |
|
|
|
if (io_thread_fd == -1) { |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
do { |
|
|
|
ret = write(io_thread_fd, &val, sizeof(val)); |
|
|
|
} while (ret < 0 && errno == EINTR); |
|
|
|
@ -258,17 +260,17 @@ static int qemu_event_init(void) |
|
|
|
int fds[2]; |
|
|
|
|
|
|
|
err = qemu_eventfd(fds); |
|
|
|
if (err == -1) |
|
|
|
if (err == -1) { |
|
|
|
return -errno; |
|
|
|
|
|
|
|
} |
|
|
|
err = fcntl_setfl(fds[0], O_NONBLOCK); |
|
|
|
if (err < 0) |
|
|
|
if (err < 0) { |
|
|
|
goto fail; |
|
|
|
|
|
|
|
} |
|
|
|
err = fcntl_setfl(fds[1], O_NONBLOCK); |
|
|
|
if (err < 0) |
|
|
|
if (err < 0) { |
|
|
|
goto fail; |
|
|
|
|
|
|
|
} |
|
|
|
qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, |
|
|
|
(void *)(unsigned long)fds[0]); |
|
|
|
|
|
|
|
@ -527,7 +529,6 @@ void pause_all_vcpus(void) |
|
|
|
|
|
|
|
void qemu_cpu_kick(void *env) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
void qemu_cpu_kick_self(void) |
|
|
|
@ -660,13 +661,15 @@ int qemu_init_main_loop(void) |
|
|
|
blocked_signals = block_io_signals(); |
|
|
|
|
|
|
|
ret = qemu_signalfd_init(blocked_signals); |
|
|
|
if (ret) |
|
|
|
if (ret) { |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
/* Note eventfd must be drained before signalfd handlers run */ |
|
|
|
ret = qemu_event_init(); |
|
|
|
if (ret) |
|
|
|
if (ret) { |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
qemu_cond_init(&qemu_pause_cond); |
|
|
|
qemu_cond_init(&qemu_system_cond); |
|
|
|
@ -696,10 +699,11 @@ void run_on_cpu(CPUState *env, void (*func)(void *data), void *data) |
|
|
|
|
|
|
|
wi.func = func; |
|
|
|
wi.data = data; |
|
|
|
if (!env->queued_work_first) |
|
|
|
if (!env->queued_work_first) { |
|
|
|
env->queued_work_first = &wi; |
|
|
|
else |
|
|
|
} else { |
|
|
|
env->queued_work_last->next = &wi; |
|
|
|
} |
|
|
|
env->queued_work_last = &wi; |
|
|
|
wi.next = NULL; |
|
|
|
wi.done = false; |
|
|
|
@ -717,8 +721,9 @@ static void flush_queued_work(CPUState *env) |
|
|
|
{ |
|
|
|
struct qemu_work_item *wi; |
|
|
|
|
|
|
|
if (!env->queued_work_first) |
|
|
|
if (!env->queued_work_first) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
while ((wi = env->queued_work_first)) { |
|
|
|
env->queued_work_first = wi->next; |
|
|
|
@ -798,12 +803,14 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) |
|
|
|
qemu_cond_signal(&qemu_cpu_cond); |
|
|
|
|
|
|
|
/* and wait for machine initialization */ |
|
|
|
while (!qemu_system_ready) |
|
|
|
while (!qemu_system_ready) { |
|
|
|
qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); |
|
|
|
} |
|
|
|
|
|
|
|
while (1) { |
|
|
|
if (cpu_can_run(env)) |
|
|
|
if (cpu_can_run(env)) { |
|
|
|
qemu_cpu_exec(env); |
|
|
|
} |
|
|
|
qemu_kvm_wait_io_event(env); |
|
|
|
} |
|
|
|
|
|
|
|
@ -819,13 +826,15 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) |
|
|
|
|
|
|
|
/* signal CPU creation */ |
|
|
|
qemu_mutex_lock(&qemu_global_mutex); |
|
|
|
for (env = first_cpu; env != NULL; env = env->next_cpu) |
|
|
|
for (env = first_cpu; env != NULL; env = env->next_cpu) { |
|
|
|
env->created = 1; |
|
|
|
} |
|
|
|
qemu_cond_signal(&qemu_cpu_cond); |
|
|
|
|
|
|
|
/* and wait for machine initialization */ |
|
|
|
while (!qemu_system_ready) |
|
|
|
while (!qemu_system_ready) { |
|
|
|
qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); |
|
|
|
} |
|
|
|
|
|
|
|
while (1) { |
|
|
|
cpu_exec_all(); |
|
|
|
@ -838,6 +847,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) |
|
|
|
void qemu_cpu_kick(void *_env) |
|
|
|
{ |
|
|
|
CPUState *env = _env; |
|
|
|
|
|
|
|
qemu_cond_broadcast(env->halt_cond); |
|
|
|
if (!env->thread_kicked) { |
|
|
|
qemu_thread_signal(env->thread, SIG_IPI); |
|
|
|
@ -889,8 +899,9 @@ static int all_vcpus_paused(void) |
|
|
|
CPUState *penv = first_cpu; |
|
|
|
|
|
|
|
while (penv) { |
|
|
|
if (!penv->stopped) |
|
|
|
if (!penv->stopped) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
penv = (CPUState *)penv->next_cpu; |
|
|
|
} |
|
|
|
|
|
|
|
@ -932,14 +943,16 @@ void resume_all_vcpus(void) |
|
|
|
static void qemu_tcg_init_vcpu(void *_env) |
|
|
|
{ |
|
|
|
CPUState *env = _env; |
|
|
|
|
|
|
|
/* share a single thread for all cpus with TCG */ |
|
|
|
if (!tcg_cpu_thread) { |
|
|
|
env->thread = qemu_mallocz(sizeof(QemuThread)); |
|
|
|
env->halt_cond = qemu_mallocz(sizeof(QemuCond)); |
|
|
|
qemu_cond_init(env->halt_cond); |
|
|
|
qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env); |
|
|
|
while (env->created == 0) |
|
|
|
while (env->created == 0) { |
|
|
|
qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); |
|
|
|
} |
|
|
|
tcg_cpu_thread = env->thread; |
|
|
|
tcg_halt_cond = env->halt_cond; |
|
|
|
} else { |
|
|
|
@ -954,8 +967,9 @@ static void qemu_kvm_start_vcpu(CPUState *env) |
|
|
|
env->halt_cond = qemu_mallocz(sizeof(QemuCond)); |
|
|
|
qemu_cond_init(env->halt_cond); |
|
|
|
qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env); |
|
|
|
while (env->created == 0) |
|
|
|
while (env->created == 0) { |
|
|
|
qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void qemu_init_vcpu(void *_env) |
|
|
|
@ -964,10 +978,11 @@ void qemu_init_vcpu(void *_env) |
|
|
|
|
|
|
|
env->nr_cores = smp_cores; |
|
|
|
env->nr_threads = smp_threads; |
|
|
|
if (kvm_enabled()) |
|
|
|
if (kvm_enabled()) { |
|
|
|
qemu_kvm_start_vcpu(env); |
|
|
|
else |
|
|
|
} else { |
|
|
|
qemu_tcg_init_vcpu(env); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void qemu_notify_event(void) |
|
|
|
@ -1050,16 +1065,18 @@ bool cpu_exec_all(void) |
|
|
|
{ |
|
|
|
int r; |
|
|
|
|
|
|
|
if (next_cpu == NULL) |
|
|
|
if (next_cpu == NULL) { |
|
|
|
next_cpu = first_cpu; |
|
|
|
} |
|
|
|
for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) { |
|
|
|
CPUState *env = next_cpu; |
|
|
|
|
|
|
|
qemu_clock_enable(vm_clock, |
|
|
|
(env->singlestep_enabled & SSTEP_NOTIMER) == 0); |
|
|
|
|
|
|
|
if (qemu_alarm_pending()) |
|
|
|
if (qemu_alarm_pending()) { |
|
|
|
break; |
|
|
|
} |
|
|
|
if (cpu_can_run(env)) { |
|
|
|
r = qemu_cpu_exec(env); |
|
|
|
if (kvm_enabled()) { |
|
|
|
|