X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=cpus.c;h=6bf4e3f005c117be0ca752eed466aa4cb4051a94;hb=ff5acedd8f472a39b2e11d0fad79d0e9b6c140c2;hp=d54ec7d0e52889b5bc432738b7127d9a432bd50a;hpb=7e97cd88148876bad36ee7c66d526dcaed328d0d;p=qemu.git diff --git a/cpus.c b/cpus.c index d54ec7d0e..6bf4e3f00 100644 --- a/cpus.c +++ b/cpus.c @@ -30,10 +30,13 @@ #include "gdbstub.h" #include "dma.h" #include "kvm.h" -#include "exec-all.h" +#include "qemu-thread.h" #include "cpus.h" + +#ifndef _WIN32 #include "compatfd.h" +#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4) @@ -130,44 +133,60 @@ 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; } -static int cpu_has_work(CPUState *env) +static bool cpu_thread_is_idle(CPUState *env) { - if (env->stop) - return 1; - if (env->queued_work_first) - return 1; - if (env->stopped || !vm_running) - return 0; - if (!env->halted) - return 1; - if (qemu_cpu_has_work(env)) - return 1; - return 0; + if (env->stop || env->queued_work_first) { + return false; + } + if (env->stopped || !vm_running) { + return true; + } + if (!env->halted || qemu_cpu_has_work(env) || + (kvm_enabled() && kvm_irqchip_in_kernel())) { + return false; + } + return true; } -static int any_cpu_has_work(void) +bool all_cpu_threads_idle(void) { CPUState *env; - for (env = first_cpu; env != NULL; env = env->next_cpu) - if (cpu_has_work(env)) - return 1; - return 0; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (!cpu_thread_is_idle(env)) { + return false; + } + } + return true; } -static void cpu_debug_handler(CPUState *env) +static void cpu_handle_guest_debug(CPUState *env) { gdb_set_stop_cpu(env); - debug_requested = EXCP_DEBUG; - vm_stop(EXCP_DEBUG); + qemu_system_debug_request(); +#ifdef CONFIG_IOTHREAD + env->stopped = 1; +#endif +} + +#ifdef CONFIG_IOTHREAD +static void cpu_signal(int sig) +{ + if (cpu_single_env) { + cpu_exit(cpu_single_env); + } + exit_request = 1; } +#endif #ifdef CONFIG_LINUX static void sigbus_reraise(void) @@ -208,11 +227,58 @@ static void qemu_init_sigbus(void) prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0); } +static void qemu_kvm_eat_signals(CPUState *env) +{ + struct timespec ts = { 0, 0 }; + siginfo_t siginfo; + sigset_t waitset; + sigset_t chkset; + int r; + + sigemptyset(&waitset); + sigaddset(&waitset, SIG_IPI); + sigaddset(&waitset, SIGBUS); + + do { + r = sigtimedwait(&waitset, &siginfo, &ts); + if (r == -1 && !(errno == EAGAIN || errno == EINTR)) { + perror("sigtimedwait"); + exit(1); + } + + switch (r) { + case SIGBUS: + if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) { + sigbus_reraise(); + } + break; + default: + break; + } + + r = sigpending(&chkset); + if (r == -1) { + perror("sigpending"); + exit(1); + } + } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS)); + +#ifndef CONFIG_IOTHREAD + if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) { + qemu_notify_event(); + } +#endif +} + #else /* !CONFIG_LINUX */ static void qemu_init_sigbus(void) { } + +static void qemu_kvm_eat_signals(CPUState *env) +{ +} #endif /* !CONFIG_LINUX */ #ifndef _WIN32 @@ -224,16 +290,16 @@ 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); /* EAGAIN is fine, a read must be pending. */ if (ret < 0 && errno != EAGAIN) { - fprintf(stderr, "qemu_event_increment: write() filed: %s\n", + fprintf(stderr, "qemu_event_increment: write() failed: %s\n", strerror(errno)); exit (1); } @@ -241,7 +307,7 @@ static void qemu_event_increment(void) static void qemu_event_read(void *opaque) { - int fd = (unsigned long)opaque; + int fd = (intptr_t)opaque; ssize_t len; char buffer[512]; @@ -257,19 +323,19 @@ 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]); + (void *)(intptr_t)fds[0]); io_thread_fd = fds[1]; return 0; @@ -290,7 +356,7 @@ static void dummy_signal(int sig) */ static void sigfd_handler(void *opaque) { - int fd = (unsigned long) opaque; + int fd = (intptr_t)opaque; struct qemu_signalfd_siginfo info; struct sigaction action; ssize_t len; @@ -319,11 +385,45 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signalfd_init(sigset_t mask) +static int qemu_signal_init(void) { int sigfd; + sigset_t set; + +#ifdef CONFIG_IOTHREAD + /* SIGUSR2 used by posix-aio-compat.c */ + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); + + /* + * SIG_IPI must be blocked in the main thread and must not be caught + * by sigwait() in the signal thread. Otherwise, the cpu thread will + * not catch it reliably. + */ + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + pthread_sigmask(SIG_BLOCK, &set, NULL); - sigfd = qemu_signalfd(&mask); + sigemptyset(&set); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIGBUS); +#else + sigemptyset(&set); + sigaddset(&set, SIGBUS); + if (kvm_enabled()) { + /* + * We need to process timer signals synchronously to avoid a race + * between exit_request check and KVM vcpu entry. + */ + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + } +#endif + pthread_sigmask(SIG_BLOCK, &set, NULL); + + sigfd = qemu_signalfd(&set); if (sigfd == -1) { fprintf(stderr, "failed to create signalfd\n"); return -errno; @@ -332,51 +432,63 @@ static int qemu_signalfd_init(sigset_t mask) fcntl_setfl(sigfd, O_NONBLOCK); qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, - (void *)(unsigned long) sigfd); + (void *)(intptr_t)sigfd); return 0; } -static void qemu_kvm_eat_signals(CPUState *env) +static void qemu_kvm_init_cpu_signals(CPUState *env) { - struct timespec ts = { 0, 0 }; - siginfo_t siginfo; - sigset_t waitset; - sigset_t chkset; int r; + sigset_t set; + struct sigaction sigact; - sigemptyset(&waitset); - sigaddset(&waitset, SIG_IPI); - sigaddset(&waitset, SIGBUS); + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = dummy_signal; + sigaction(SIG_IPI, &sigact, NULL); - do { - r = sigtimedwait(&waitset, &siginfo, &ts); - if (r == -1 && !(errno == EAGAIN || errno == EINTR)) { - perror("sigtimedwait"); - exit(1); - } +#ifdef CONFIG_IOTHREAD + pthread_sigmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + sigdelset(&set, SIGBUS); + r = kvm_set_signal_mask(env, &set); + if (r) { + fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); + exit(1); + } +#else + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + pthread_sigmask(SIG_BLOCK, &set, NULL); - switch (r) { - case SIGBUS: - if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) { - sigbus_reraise(); - } - break; - default: - break; - } + pthread_sigmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIGIO); + sigdelset(&set, SIGALRM); +#endif + sigdelset(&set, SIG_IPI); + sigdelset(&set, SIGBUS); + r = kvm_set_signal_mask(env, &set); + if (r) { + fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); + exit(1); + } +} - r = sigpending(&chkset); - if (r == -1) { - perror("sigpending"); - exit(1); - } - } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS)); +static void qemu_tcg_init_cpu_signals(void) +{ +#ifdef CONFIG_IOTHREAD + sigset_t set; + struct sigaction sigact; -#ifndef CONFIG_IOTHREAD - if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) { - qemu_notify_event(); - } + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = cpu_signal; + sigaction(SIG_IPI, &sigact, NULL); + + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); #endif } @@ -408,76 +520,30 @@ static void qemu_event_increment(void) } } -static void qemu_kvm_eat_signals(CPUState *env) +static int qemu_signal_init(void) { + return 0; } -#endif /* _WIN32 */ -#ifndef CONFIG_IOTHREAD static void qemu_kvm_init_cpu_signals(CPUState *env) { -#ifndef _WIN32 - int r; - sigset_t set; - struct sigaction sigact; - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = dummy_signal; - sigaction(SIG_IPI, &sigact, NULL); - - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - pthread_sigmask(SIG_BLOCK, NULL, &set); - sigdelset(&set, SIG_IPI); - sigdelset(&set, SIGBUS); - sigdelset(&set, SIGIO); - sigdelset(&set, SIGALRM); - r = kvm_set_signal_mask(env, &set); - if (r) { - fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); - exit(1); - } -#endif + abort(); } -#ifndef _WIN32 -static sigset_t block_synchronous_signals(void) +static void qemu_tcg_init_cpu_signals(void) { - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGBUS); - if (kvm_enabled()) { - /* - * We need to process timer signals synchronously to avoid a race - * between exit_request check and KVM vcpu entry. - */ - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - } - - return set; } -#endif +#endif /* _WIN32 */ +#ifndef CONFIG_IOTHREAD int qemu_init_main_loop(void) { -#ifndef _WIN32 - sigset_t blocked_signals; int ret; - blocked_signals = block_synchronous_signals(); - - ret = qemu_signalfd_init(blocked_signals); + ret = qemu_signal_init(); if (ret) { return ret; } -#endif - cpu_set_debug_excp_handler(cpu_debug_handler); qemu_init_sigbus(); @@ -503,10 +569,12 @@ void qemu_init_vcpu(void *_env) exit(1); } qemu_kvm_init_cpu_signals(env); + } else { + qemu_tcg_init_cpu_signals(); } } -int qemu_cpu_self(void *env) +int qemu_cpu_is_self(void *env) { return 1; } @@ -526,7 +594,6 @@ void pause_all_vcpus(void) void qemu_cpu_kick(void *env) { - return; } void qemu_cpu_kick_self(void) @@ -568,10 +635,9 @@ void vm_stop(int reason) #else /* CONFIG_IOTHREAD */ -#include "qemu-thread.h" - QemuMutex qemu_global_mutex; -static QemuMutex qemu_fair_mutex; +static QemuCond qemu_io_proceeded_cond; +static bool iothread_requesting_mutex; static QemuThread io_thread; @@ -586,94 +652,32 @@ static QemuCond qemu_system_cond; static QemuCond qemu_pause_cond; static QemuCond qemu_work_cond; -static void cpu_signal(int sig) -{ - if (cpu_single_env) { - cpu_exit(cpu_single_env); - } - exit_request = 1; -} - -static void qemu_kvm_init_cpu_signals(CPUState *env) -{ - int r; - sigset_t set; - struct sigaction sigact; - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = dummy_signal; - sigaction(SIG_IPI, &sigact, NULL); - - pthread_sigmask(SIG_BLOCK, NULL, &set); - sigdelset(&set, SIG_IPI); - sigdelset(&set, SIGBUS); - r = kvm_set_signal_mask(env, &set); - if (r) { - fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); - exit(1); - } -} - -static void qemu_tcg_init_cpu_signals(void) -{ - sigset_t set; - struct sigaction sigact; - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = cpu_signal; - sigaction(SIG_IPI, &sigact, NULL); - - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); -} - -static sigset_t block_io_signals(void) -{ - sigset_t set; - - /* SIGUSR2 used by posix-aio-compat.c */ - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); - - sigemptyset(&set); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIG_IPI); - sigaddset(&set, SIGBUS); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - return set; -} - int qemu_init_main_loop(void) { int ret; - sigset_t blocked_signals; - - cpu_set_debug_excp_handler(cpu_debug_handler); qemu_init_sigbus(); - blocked_signals = block_io_signals(); - - ret = qemu_signalfd_init(blocked_signals); - if (ret) + ret = qemu_signal_init(); + 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_cpu_cond); qemu_cond_init(&qemu_system_cond); - qemu_mutex_init(&qemu_fair_mutex); + qemu_cond_init(&qemu_pause_cond); + qemu_cond_init(&qemu_work_cond); + qemu_cond_init(&qemu_io_proceeded_cond); qemu_mutex_init(&qemu_global_mutex); qemu_mutex_lock(&qemu_global_mutex); - qemu_thread_self(&io_thread); + qemu_thread_get_self(&io_thread); return 0; } @@ -688,17 +692,18 @@ void run_on_cpu(CPUState *env, void (*func)(void *data), void *data) { struct qemu_work_item wi; - if (qemu_cpu_self(env)) { + if (qemu_cpu_is_self(env)) { func(data); return; } 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; @@ -716,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; @@ -743,20 +749,16 @@ static void qemu_tcg_wait_io_event(void) { CPUState *env; - while (!any_cpu_has_work()) - qemu_cond_timedwait(tcg_halt_cond, &qemu_global_mutex, 1000); - - qemu_mutex_unlock(&qemu_global_mutex); - - /* - * Users of qemu_global_mutex can be starved, having no chance - * to acquire it since this path will get to it first. - * So use another lock to provide fairness. - */ - qemu_mutex_lock(&qemu_fair_mutex); - qemu_mutex_unlock(&qemu_fair_mutex); + while (all_cpu_threads_idle()) { + /* Start accounting real time to the virtual clock if the CPUs + are idle. */ + qemu_clock_warp(vm_clock); + qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex); + } - qemu_mutex_lock(&qemu_global_mutex); + while (iothread_requesting_mutex) { + qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex); + } for (env = first_cpu; env != NULL; env = env->next_cpu) { qemu_wait_io_event_common(env); @@ -765,22 +767,22 @@ static void qemu_tcg_wait_io_event(void) static void qemu_kvm_wait_io_event(CPUState *env) { - while (!cpu_has_work(env)) - qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); + while (cpu_thread_is_idle(env)) { + qemu_cond_wait(env->halt_cond, &qemu_global_mutex); + } qemu_kvm_eat_signals(env); qemu_wait_io_event_common(env); } -static int qemu_cpu_exec(CPUState *env); - static void *qemu_kvm_cpu_thread_fn(void *arg) { CPUState *env = arg; int r; qemu_mutex_lock(&qemu_global_mutex); - qemu_thread_self(env->thread); + qemu_thread_get_self(env->thread); + env->thread_id = qemu_get_thread_id(); r = kvm_init_vcpu(env); if (r < 0) { @@ -795,12 +797,17 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) qemu_cond_signal(&qemu_cpu_cond); /* and wait for machine initialization */ - while (!qemu_system_ready) - qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); + while (!qemu_system_ready) { + qemu_cond_wait(&qemu_system_cond, &qemu_global_mutex); + } while (1) { - if (cpu_can_run(env)) - qemu_cpu_exec(env); + if (cpu_can_run(env)) { + r = kvm_cpu_exec(env); + if (r == EXCP_DEBUG) { + cpu_handle_guest_debug(env); + } + } qemu_kvm_wait_io_event(env); } @@ -812,54 +819,81 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) CPUState *env = arg; qemu_tcg_init_cpu_signals(); - qemu_thread_self(env->thread); + qemu_thread_get_self(env->thread); /* 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->thread_id = qemu_get_thread_id(); env->created = 1; + } qemu_cond_signal(&qemu_cpu_cond); /* and wait for machine initialization */ - while (!qemu_system_ready) - qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); + while (!qemu_system_ready) { + qemu_cond_wait(&qemu_system_cond, &qemu_global_mutex); + } while (1) { cpu_exec_all(); + if (use_icount && qemu_next_icount_deadline() <= 0) { + qemu_notify_event(); + } qemu_tcg_wait_io_event(); } return NULL; } +static void qemu_cpu_kick_thread(CPUState *env) +{ +#ifndef _WIN32 + int err; + + err = pthread_kill(env->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->thread->thread); + cpu_signal(0); + ResumeThread(env->thread->thread); + } +#endif +} + 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); + qemu_cpu_kick_thread(env); env->thread_kicked = true; } } void qemu_cpu_kick_self(void) { +#ifndef _WIN32 assert(cpu_single_env); if (!cpu_single_env->thread_kicked) { - qemu_thread_signal(cpu_single_env->thread, SIG_IPI); + qemu_cpu_kick_thread(cpu_single_env); cpu_single_env->thread_kicked = true; } +#else + abort(); +#endif } -int qemu_cpu_self(void *_env) +int qemu_cpu_is_self(void *_env) { CPUState *env = _env; - QemuThread this; - - qemu_thread_self(&this); - return qemu_thread_equal(&this, env->thread); + return qemu_thread_is_self(env->thread); } void qemu_mutex_lock_iothread(void) @@ -867,12 +901,13 @@ void qemu_mutex_lock_iothread(void) if (kvm_enabled()) { qemu_mutex_lock(&qemu_global_mutex); } else { - qemu_mutex_lock(&qemu_fair_mutex); + iothread_requesting_mutex = true; if (qemu_mutex_trylock(&qemu_global_mutex)) { - qemu_thread_signal(tcg_cpu_thread, SIG_IPI); + qemu_cpu_kick_thread(first_cpu); qemu_mutex_lock(&qemu_global_mutex); } - qemu_mutex_unlock(&qemu_fair_mutex); + iothread_requesting_mutex = false; + qemu_cond_broadcast(&qemu_io_proceeded_cond); } } @@ -886,8 +921,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; } @@ -905,7 +941,7 @@ void pause_all_vcpus(void) } while (!all_vcpus_paused()) { - qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); + qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex); penv = first_cpu; while (penv) { qemu_cpu_kick(penv); @@ -929,14 +965,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) - qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); + while (env->created == 0) { + qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); + } tcg_cpu_thread = env->thread; tcg_halt_cond = env->halt_cond; } else { @@ -951,8 +989,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) - qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); + while (env->created == 0) { + qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); + } } void qemu_init_vcpu(void *_env) @@ -961,10 +1000,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) @@ -972,26 +1012,19 @@ void qemu_notify_event(void) qemu_event_increment(); } -static void qemu_system_vmstop_request(int reason) -{ - vmstop_requested = reason; - qemu_notify_event(); -} - void cpu_stop_current(void) { if (cpu_single_env) { + cpu_single_env->stop = 0; cpu_single_env->stopped = 1; cpu_exit(cpu_single_env); + qemu_cond_signal(&qemu_pause_cond); } } void vm_stop(int reason) { - QemuThread me; - qemu_thread_self(&me); - - if (!qemu_thread_equal(&me, &io_thread)) { + if (!qemu_thread_is_self(&io_thread)) { qemu_system_vmstop_request(reason); /* * FIXME: should not return to device code in case @@ -1005,7 +1038,7 @@ void vm_stop(int reason) #endif -static int qemu_cpu_exec(CPUState *env) +static int tcg_cpu_exec(CPUState *env) { int ret; #ifdef CONFIG_PROFILER @@ -1021,7 +1054,7 @@ static int qemu_cpu_exec(CPUState *env) qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 0; env->icount_extra = 0; - count = qemu_icount_round (qemu_next_deadline()); + count = qemu_icount_round(qemu_next_icount_deadline()); qemu_icount += count; decr = (count > 0xffff) ? 0xffff : count; count -= decr; @@ -1047,30 +1080,40 @@ bool cpu_exec_all(void) { int r; - if (next_cpu == NULL) + /* Account partial waits to the vm_clock. */ + qemu_clock_warp(vm_clock); + + 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()) +#ifndef CONFIG_IOTHREAD + if (qemu_alarm_pending()) { break; + } +#endif if (cpu_can_run(env)) { - r = qemu_cpu_exec(env); if (kvm_enabled()) { + r = kvm_cpu_exec(env); qemu_kvm_eat_signals(env); + } else { + r = tcg_cpu_exec(env); } if (r == EXCP_DEBUG) { + cpu_handle_guest_debug(env); break; } - } else if (env->stop) { + } else if (env->stop || env->stopped) { break; } } exit_request = 0; - return any_cpu_has_work(); + return !all_cpu_threads_idle(); } void set_numa_modes(void) @@ -1103,6 +1146,11 @@ void set_cpu_log(const char *optarg) cpu_set_log(mask); } +void set_cpu_log_filename(const char *optarg) +{ + cpu_set_log_filename(optarg); +} + /* Return the virtual CPU time, based on the instruction counter. */ int64_t cpu_get_icount(void) {