if (env->stopped || !vm_running) {
return true;
}
- if (!env->halted || qemu_cpu_has_work(env)) {
+ if (!env->halted || qemu_cpu_has_work(env) ||
+ (kvm_enabled() && kvm_irqchip_in_kernel())) {
return false;
}
return true;
}
-static bool all_cpu_threads_idle(void)
+bool all_cpu_threads_idle(void)
{
CPUState *env;
return true;
}
-static CPUDebugExcpHandler *debug_excp_handler;
-
-CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
-{
- CPUDebugExcpHandler *old_handler = debug_excp_handler;
-
- debug_excp_handler = handler;
- return old_handler;
-}
-
-static void cpu_handle_debug_exception(CPUState *env)
+static void cpu_handle_guest_debug(CPUState *env)
{
- CPUWatchpoint *wp;
-
- if (!env->watchpoint_hit) {
- QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
- wp->flags &= ~BP_WATCHPOINT_HIT;
- }
- }
- if (debug_excp_handler) {
- debug_excp_handler(env);
- }
-
gdb_set_stop_cpu(env);
qemu_system_debug_request();
#ifdef CONFIG_IOTHREAD
#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)
{
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
static void qemu_event_read(void *opaque)
{
- int fd = (unsigned long)opaque;
+ int fd = (intptr_t)opaque;
ssize_t len;
char buffer[512];
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;
*/
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;
}
}
-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);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIG_IPI);
+ sigaddset(&set, SIGBUS);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+#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
- sigfd = qemu_signalfd(&mask);
+ sigfd = qemu_signalfd(&set);
if (sigfd == -1) {
fprintf(stderr, "failed to create signalfd\n");
return -errno;
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
}
}
}
-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
qemu_init_sigbus();
exit(1);
}
qemu_kvm_init_cpu_signals(env);
+ } else {
+ qemu_tcg_init_cpu_signals();
}
}
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;
qemu_init_sigbus();
- blocked_signals = block_io_signals();
-
- ret = qemu_signalfd_init(blocked_signals);
+ ret = qemu_signal_init();
if (ret) {
return ret;
}
CPUState *env;
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);
qemu_thread_get_self(env->thread);
+ env->thread_id = qemu_get_thread_id();
r = kvm_init_vcpu(env);
if (r < 0) {
if (cpu_can_run(env)) {
r = kvm_cpu_exec(env);
if (r == EXCP_DEBUG) {
- cpu_handle_debug_exception(env);
+ cpu_handle_guest_debug(env);
}
}
qemu_kvm_wait_io_event(env);
/* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
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);
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_is_self(void *_env)
} else {
qemu_mutex_lock(&qemu_fair_mutex);
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);
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);
+ qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
tcg_cpu_thread = env->thread;
tcg_halt_cond = env->halt_cond;
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);
+ qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
}
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;
{
int r;
+ /* Account partial waits to the vm_clock. */
+ qemu_clock_warp(vm_clock);
+
if (next_cpu == NULL) {
next_cpu = first_cpu;
}
qemu_clock_enable(vm_clock,
(env->singlestep_enabled & SSTEP_NOTIMER) == 0);
+#ifndef CONFIG_IOTHREAD
if (qemu_alarm_pending()) {
break;
}
+#endif
if (cpu_can_run(env)) {
if (kvm_enabled()) {
r = kvm_cpu_exec(env);
r = tcg_cpu_exec(env);
}
if (r == EXCP_DEBUG) {
- cpu_handle_debug_exception(env);
+ cpu_handle_guest_debug(env);
break;
}
} else if (env->stop || env->stopped) {