* [Qemu-devel] [patch 01/11] qemu: create helper for event notification
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers Marcelo Tosatti
` (9 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: abstract-qemu-event --]
[-- Type: text/plain, Size: 3776 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -1183,9 +1183,8 @@ void qemu_mod_timer(QEMUTimer *ts, int64
qemu_rearm_alarm_timer(alarm_timer);
}
/* Interrupt execution to force deadline recalculation. */
- if (use_icount && cpu_single_env) {
- cpu_exit(cpu_single_env);
- }
+ if (use_icount)
+ qemu_notify_event();
}
}
@@ -1338,8 +1337,6 @@ static void host_alarm_handler(int host_
qemu_get_clock(vm_clock))) ||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
- CPUState *env = next_cpu;
-
#ifdef _WIN32
struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
SetEvent(data->host_alarm);
@@ -1349,16 +1346,7 @@ static void host_alarm_handler(int host_
#endif
alarm_timer->flags |= ALARM_FLAG_EXPIRED;
- if (env) {
- /* stop the currently executing cpu because a timer occured */
- cpu_exit(env);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
- event_pending = 1;
+ qemu_notify_event();
}
}
@@ -3334,15 +3322,7 @@ static int ram_load(QEMUFile *f, void *o
void qemu_service_io(void)
{
- CPUState *env = cpu_single_env;
- if (env) {
- cpu_exit(env);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
+ qemu_notify_event();
}
/***********************************************************/
@@ -3410,15 +3390,12 @@ void qemu_bh_schedule_idle(QEMUBH *bh)
void qemu_bh_schedule(QEMUBH *bh)
{
- CPUState *env = cpu_single_env;
if (bh->scheduled)
return;
bh->scheduled = 1;
bh->idle = 0;
/* stop the currently executing CPU to execute the BH ASAP */
- if (env) {
- cpu_exit(env);
- }
+ qemu_notify_event();
}
void qemu_bh_cancel(QEMUBH *bh)
@@ -3627,22 +3604,32 @@ void qemu_system_reset_request(void)
} else {
reset_requested = 1;
}
- if (cpu_single_env)
- cpu_exit(cpu_single_env);
+ qemu_notify_event();
}
void qemu_system_shutdown_request(void)
{
shutdown_requested = 1;
- if (cpu_single_env)
- cpu_exit(cpu_single_env);
+ qemu_notify_event();
}
void qemu_system_powerdown_request(void)
{
powerdown_requested = 1;
- if (cpu_single_env)
- cpu_exit(cpu_single_env);
+ qemu_notify_event();
+}
+
+void qemu_notify_event(void)
+{
+ CPUState *env = cpu_single_env;
+
+ if (env) {
+ cpu_exit(env);
+#ifdef USE_KQEMU
+ if (env->kqemu_enabled)
+ kqemu_cpu_interrupt(env);
+#endif
+ }
}
#ifdef _WIN32
Index: trunk/qemu-common.h
===================================================================
--- trunk.orig/qemu-common.h
+++ trunk/qemu-common.h
@@ -186,6 +186,9 @@ int cpu_load(QEMUFile *f, void *opaque,
/* Force QEMU to stop what it's doing and service IO */
void qemu_service_io(void);
+/* Force QEMU to process pending events */
+void qemu_notify_event(void);
+
typedef struct QEMUIOVector {
struct iovec *iov;
int niov;
Index: trunk/hw/mac_dbdma.c
===================================================================
--- trunk.orig/hw/mac_dbdma.c
+++ trunk/hw/mac_dbdma.c
@@ -651,9 +651,7 @@ void DBDMA_register_channel(void *dbdma,
void DBDMA_schedule(void)
{
- CPUState *env = cpu_single_env;
- if (env)
- cpu_exit(env);
+ qemu_notify_event();
}
static void
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 01/11] qemu: create helper for event notification Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-06 18:21 ` Anthony Liguori
2009-04-02 23:32 ` [Qemu-devel] [patch 03/11] qemu: per-arch cpu_has_work Marcelo Tosatti
` (8 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: iothread-mutex --]
[-- Type: text/plain, Size: 5230 bytes --]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/qemu-thread.c
===================================================================
--- /dev/null
+++ trunk/qemu-thread.c
@@ -0,0 +1,151 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include "qemu-thread.h"
+
+static void error_exit(int err, const char *msg)
+{
+ fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
+ exit(1);
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_mutex_init(&mutex->lock, NULL);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_mutex_lock(&mutex->lock);
+ if (err)
+ error_exit(err, __func__);
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+ return pthread_mutex_trylock(&mutex->lock);
+}
+
+static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
+{
+ ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
+ ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
+ if (ts->tv_nsec >= 1000000000) {
+ ts->tv_nsec -= 1000000000;
+ ts->tv_sec++;
+ }
+}
+
+int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
+{
+ int err;
+ struct timespec ts;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ timespec_add_ms(&ts, msecs);
+
+ err = pthread_mutex_timedlock(&mutex->lock, &ts);
+ if (err && err != ETIMEDOUT)
+ error_exit(err, __func__);
+ return err;
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_mutex_unlock(&mutex->lock);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+ int err;
+
+ err = pthread_cond_init(&cond->cond, NULL);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+ int err;
+
+ err = pthread_cond_signal(&cond->cond);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+ int err;
+
+ err = pthread_cond_broadcast(&cond->cond);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_cond_wait(&cond->cond, &mutex->lock);
+ if (err)
+ error_exit(err, __func__);
+}
+
+int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
+{
+ struct timespec ts;
+ int err;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ timespec_add_ms(&ts, msecs);
+
+ err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
+ if (err && err != ETIMEDOUT)
+ error_exit(err, __func__);
+ return err;
+}
+
+void qemu_thread_create(QemuThread *thread,
+ void *(*start_routine)(void*),
+ void *arg)
+{
+ int err;
+
+ err = pthread_create(&thread->thread, NULL, start_routine, arg);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_thread_signal(QemuThread *thread, int sig)
+{
+ int err;
+
+ err = pthread_kill(thread->thread, sig);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_thread_self(QemuThread *thread)
+{
+ thread->thread = pthread_self();
+}
+
+int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
+{
+ return (thread1->thread == thread2->thread);
+}
+
Index: trunk/qemu-thread.h
===================================================================
--- /dev/null
+++ trunk/qemu-thread.h
@@ -0,0 +1,40 @@
+#ifndef __QEMU_THREAD_H
+#define __QEMU_THREAD_H 1
+#include "semaphore.h"
+#include "pthread.h"
+
+struct QemuMutex {
+ pthread_mutex_t lock;
+};
+
+struct QemuCond {
+ pthread_cond_t cond;
+};
+
+struct QemuThread {
+ pthread_t thread;
+};
+
+typedef struct QemuMutex QemuMutex;
+typedef struct QemuCond QemuCond;
+typedef struct QemuThread QemuThread;
+
+void qemu_mutex_init(QemuMutex *mutex);
+void qemu_mutex_lock(QemuMutex *mutex);
+int qemu_mutex_trylock(QemuMutex *mutex);
+int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs);
+void qemu_mutex_unlock(QemuMutex *mutex);
+
+void qemu_cond_init(QemuCond *cond);
+void qemu_cond_signal(QemuCond *cond);
+void qemu_cond_broadcast(QemuCond *cond);
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
+int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs);
+
+void qemu_thread_create(QemuThread *thread,
+ void *(*start_routine)(void*),
+ void *arg);
+void qemu_thread_signal(QemuThread *thread, int sig);
+void qemu_thread_self(QemuThread *thread);
+int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2);
+#endif
Index: trunk/Makefile.target
===================================================================
--- trunk.orig/Makefile.target
+++ trunk/Makefile.target
@@ -501,6 +501,7 @@ endif #CONFIG_BSD_USER
ifndef CONFIG_USER_ONLY
OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o dma-helpers.o
+OBJS+=qemu-thread.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers
2009-04-02 23:32 ` [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers Marcelo Tosatti
@ 2009-04-06 18:21 ` Anthony Liguori
2009-04-06 19:20 ` Marcelo Tosatti
0 siblings, 1 reply; 16+ messages in thread
From: Anthony Liguori @ 2009-04-06 18:21 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
This patch breaks the build on win32. Even with all of the patches
applied, the win32 build is broken.
Marcelo Tosatti wrote:
> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
>
> Index: trunk/qemu-thread.c
> ===================================================================
> --- /dev/null
> +++ trunk/qemu-thread.c
>
Please make sure to include Copyright/License information in all new files.
--
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers
2009-04-06 18:21 ` Anthony Liguori
@ 2009-04-06 19:20 ` Marcelo Tosatti
2009-04-06 19:35 ` Anthony Liguori
0 siblings, 1 reply; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-06 19:20 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Mon, Apr 06, 2009 at 01:21:09PM -0500, Anthony Liguori wrote:
> This patch breaks the build on win32. Even with all of the patches
> applied, the win32 build is broken.
qemu-thread.c compilation fails? Can you show the logs please?
Need to skip qemu-thread.c in the Makefile for WIN32.
> Marcelo Tosatti wrote:
>> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
>>
>> Index: trunk/qemu-thread.c
>> ===================================================================
>> --- /dev/null
>> +++ trunk/qemu-thread.c
>>
>
> Please make sure to include Copyright/License information in all new files.
Will do.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers
2009-04-06 19:20 ` Marcelo Tosatti
@ 2009-04-06 19:35 ` Anthony Liguori
0 siblings, 0 replies; 16+ messages in thread
From: Anthony Liguori @ 2009-04-06 19:35 UTC (permalink / raw)
To: qemu-devel
Marcelo Tosatti wrote:
> On Mon, Apr 06, 2009 at 01:21:09PM -0500, Anthony Liguori wrote:
>
>> This patch breaks the build on win32. Even with all of the patches
>> applied, the win32 build is broken.
>>
>
> qemu-thread.c compilation fails? Can you show the logs please?
>
> Need to skip qemu-thread.c in the Makefile for WIN32.
>
It's trying to build qemu-thread.c on WIN32 which uses pthreads which
isn't present on WIN32 so that's the source of the error.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 03/11] qemu: per-arch cpu_has_work
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 01/11] qemu: create helper for event notification Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 02/11] qemu: mutex/thread/cond wrappers Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 04/11] qemu: introduce main_loop_break Marcelo Tosatti
` (7 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: qemu-arch-has-work --]
[-- Type: text/plain, Size: 6922 bytes --]
Blue Swirl: fix Sparc32 breakage
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/target-alpha/exec.h
===================================================================
--- trunk.orig/target-alpha/exec.h
+++ trunk/target-alpha/exec.h
@@ -48,10 +48,15 @@ static always_inline void regs_to_env(vo
{
}
+static always_inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
static always_inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
Index: trunk/target-i386/exec.h
===================================================================
--- trunk.orig/target-i386/exec.h
+++ trunk/target-i386/exec.h
@@ -338,14 +338,23 @@ static inline void regs_to_env(void)
#endif
}
+static inline int cpu_has_work(CPUState *env)
+{
+ int work;
+
+ work = (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->eflags & IF_MASK);
+ work |= env->interrupt_request & CPU_INTERRUPT_NMI;
+
+ return work;
+}
+
static inline int cpu_halted(CPUState *env) {
/* handle exit of HALTED state */
if (!env->halted)
return 0;
/* disable halt condition */
- if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
- (env->eflags & IF_MASK)) ||
- (env->interrupt_request & CPU_INTERRUPT_NMI)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
Index: trunk/cpu-all.h
===================================================================
--- trunk.orig/cpu-all.h
+++ trunk/cpu-all.h
@@ -775,6 +775,8 @@ void cpu_reset_interrupt(CPUState *env,
void cpu_exit(CPUState *s);
+int qemu_cpu_has_work(CPUState *env);
+
/* Breakpoint/watchpoint flags */
#define BP_MEM_READ 0x01
#define BP_MEM_WRITE 0x02
Index: trunk/cpu-exec.c
===================================================================
--- trunk.orig/cpu-exec.c
+++ trunk/cpu-exec.c
@@ -50,6 +50,11 @@ int tb_invalidated_flag;
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
+int qemu_cpu_has_work(CPUState *env)
+{
+ return cpu_has_work(env);
+}
+
void cpu_loop_exit(void)
{
/* NOTE: the register at this point must be saved by hand because
Index: trunk/target-arm/exec.h
===================================================================
--- trunk.orig/target-arm/exec.h
+++ trunk/target-arm/exec.h
@@ -37,14 +37,19 @@ static inline void regs_to_env(void)
{
}
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request &
+ (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB));
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
/* An interrupt wakes the CPU even if the I and F CPSR bits are
set. We use EXITTB to silently wake CPU without causing an
actual interrupt. */
- if (env->interrupt_request &
- (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
Index: trunk/target-cris/exec.h
===================================================================
--- trunk.orig/target-cris/exec.h
+++ trunk/target-cris/exec.h
@@ -40,6 +40,11 @@ static inline void regs_to_env(void)
void cpu_cris_flush_flags(CPUCRISState *env, int cc_op);
void helper_movec(CPUCRISState *env, int reg, uint32_t val);
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI));
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
Index: trunk/target-m68k/exec.h
===================================================================
--- trunk.orig/target-m68k/exec.h
+++ trunk/target-m68k/exec.h
@@ -41,10 +41,15 @@ static inline void regs_to_env(void)
#include "softmmu_exec.h"
#endif
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & (CPU_INTERRUPT_HARD));
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
Index: trunk/target-mips/exec.h
===================================================================
--- trunk.orig/target-mips/exec.h
+++ trunk/target-mips/exec.h
@@ -33,12 +33,18 @@ static inline void regs_to_env(void)
{
}
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request &
+ (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER));
+}
+
+
static inline int cpu_halted(CPUState *env)
{
if (!env->halted)
return 0;
- if (env->interrupt_request &
- (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
Index: trunk/target-ppc/exec.h
===================================================================
--- trunk.orig/target-ppc/exec.h
+++ trunk/target-ppc/exec.h
@@ -44,11 +44,17 @@ static always_inline void regs_to_env (v
{
}
+static always_inline int cpu_has_work(CPUState *env)
+{
+ return (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD));
+}
+
+
static always_inline int cpu_halted (CPUState *env)
{
if (!env->halted)
return 0;
- if (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
Index: trunk/target-sh4/exec.h
===================================================================
--- trunk.orig/target-sh4/exec.h
+++ trunk/target-sh4/exec.h
@@ -28,10 +28,15 @@ register struct CPUSH4State *env asm(ARE
#include "cpu.h"
#include "exec-all.h"
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_has_work(env)) {
env->halted = 0;
env->intr_at_halt = 1;
return 0;
Index: trunk/target-sparc/exec.h
===================================================================
--- trunk.orig/target-sparc/exec.h
+++ trunk/target-sparc/exec.h
@@ -24,10 +24,17 @@ static inline void regs_to_env(void)
/* op_helper.c */
void do_interrupt(CPUState *env);
+static inline int cpu_has_work(CPUState *env1)
+{
+ return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env1->psret != 0);
+}
+
+
static inline int cpu_halted(CPUState *env1) {
if (!env1->halted)
return 0;
- if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && (env1->psret != 0)) {
+ if (cpu_has_work(env1)) {
env1->halted = 0;
return 0;
}
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 04/11] qemu: introduce main_loop_break
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (2 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 03/11] qemu: per-arch cpu_has_work Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 05/11] qemu: separate thread for io Marcelo Tosatti
` (6 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: pipefd --]
[-- Type: text/plain, Size: 2392 bytes --]
Use a pipe to signal pending work for the iothread.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/qemu-common.h
===================================================================
--- trunk.orig/qemu-common.h
+++ trunk/qemu-common.h
@@ -186,6 +186,8 @@ int cpu_load(QEMUFile *f, void *opaque,
/* Force QEMU to stop what it's doing and service IO */
void qemu_service_io(void);
+void main_loop_break(void);
+
/* Force QEMU to process pending events */
void qemu_notify_event(void);
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -276,6 +276,8 @@ static QEMUTimer *nographic_timer;
uint8_t qemu_uuid[16];
+static int io_thread_fd = -1;
+
/***********************************************************/
/* x86 ISA bus support */
@@ -3632,6 +3634,55 @@ void qemu_notify_event(void)
}
}
+void main_loop_break(void)
+{
+ uint64_t value = 1;
+ char buffer[8];
+ size_t offset = 0;
+
+ if (io_thread_fd == -1)
+ return;
+
+ memcpy(buffer, &value, sizeof(value));
+
+ while (offset < 8) {
+ ssize_t len;
+
+ len = write(io_thread_fd, buffer + offset, 8 - offset);
+ if (len == -1 && errno == EINTR)
+ continue;
+
+ if (len <= 0)
+ break;
+
+ offset += len;
+ }
+
+ if (offset != 8)
+ fprintf(stderr, "failed to notify io thread\n");
+}
+
+/* Used to break IO thread out of select */
+static void io_thread_wakeup(void *opaque)
+{
+ int fd = (unsigned long)opaque;
+ char buffer[8];
+ size_t offset = 0;
+
+ while (offset < 8) {
+ ssize_t len;
+
+ len = read(fd, buffer + offset, 8 - offset);
+ if (len == -1 && errno == EINTR)
+ continue;
+
+ if (len <= 0)
+ break;
+
+ offset += len;
+ }
+}
+
#ifdef _WIN32
static void host_main_loop_wait(int *timeout)
{
@@ -3774,6 +3825,20 @@ void main_loop_wait(int timeout)
}
+static void setup_iothread_fd(void)
+{
+ int fds[2];
+
+ if (pipe(fds) == -1) {
+ fprintf(stderr, "failed to create iothread pipe");
+ exit(0);
+ }
+
+ qemu_set_fd_handler2(fds[0], NULL, io_thread_wakeup, NULL,
+ (void *)(unsigned long)fds[0]);
+ io_thread_fd = fds[1];
+}
+
static int main_loop(void)
{
int ret, timeout;
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 05/11] qemu: separate thread for io
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (3 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 04/11] qemu: introduce main_loop_break Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 06/11] qemu: per-cpu thread information Marcelo Tosatti
` (5 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: introduce-io-thread --]
[-- Type: text/plain, Size: 8417 bytes --]
Introduce a thread to handle host IO events.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/qemu-common.h
===================================================================
--- trunk.orig/qemu-common.h
+++ trunk/qemu-common.h
@@ -191,6 +191,10 @@ void main_loop_break(void);
/* Force QEMU to process pending events */
void qemu_notify_event(void);
+/* Unblock cpu */
+void qemu_cpu_kick(void *env);
+int qemu_cpu_self(void *env);
+
typedef struct QEMUIOVector {
struct iovec *iov;
int niov;
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -146,6 +146,7 @@ int main(int argc, char **argv)
#include "gdbstub.h"
#include "qemu-timer.h"
#include "qemu-char.h"
+#include "qemu-thread.h"
#include "cache-utils.h"
#include "block.h"
#include "dma.h"
@@ -278,6 +279,13 @@ uint8_t qemu_uuid[16];
static int io_thread_fd = -1;
+QemuMutex qemu_global_mutex;
+QemuMutex qemu_fair_mutex;
+
+QemuThread io_thread;
+QemuThread cpus_thread;
+QemuCond halt_cond;
+
/***********************************************************/
/* x86 ISA bus support */
@@ -1347,8 +1355,6 @@ static void host_alarm_handler(int host_
write(alarm_timer_wfd, &byte, sizeof(byte));
#endif
alarm_timer->flags |= ALARM_FLAG_EXPIRED;
-
- qemu_notify_event();
}
}
@@ -2957,6 +2963,7 @@ int qemu_set_fd_handler2(int fd,
ioh->opaque = opaque;
ioh->deleted = 0;
}
+ main_loop_break();
return 0;
}
@@ -3324,7 +3331,6 @@ static int ram_load(QEMUFile *f, void *o
void qemu_service_io(void)
{
- qemu_notify_event();
}
/***********************************************************/
@@ -3397,7 +3403,7 @@ void qemu_bh_schedule(QEMUBH *bh)
bh->scheduled = 1;
bh->idle = 0;
/* stop the currently executing CPU to execute the BH ASAP */
- qemu_notify_event();
+ main_loop_break();
}
void qemu_bh_cancel(QEMUBH *bh)
@@ -3606,32 +3612,24 @@ void qemu_system_reset_request(void)
} else {
reset_requested = 1;
}
- qemu_notify_event();
+ main_loop_break();
}
void qemu_system_shutdown_request(void)
{
shutdown_requested = 1;
- qemu_notify_event();
+ main_loop_break();
}
void qemu_system_powerdown_request(void)
{
powerdown_requested = 1;
- qemu_notify_event();
+ main_loop_break();
}
void qemu_notify_event(void)
{
- CPUState *env = cpu_single_env;
-
- if (env) {
- cpu_exit(env);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled)
- kqemu_cpu_interrupt(env);
-#endif
- }
+ main_loop_break();
}
void main_loop_break(void)
@@ -3733,6 +3731,105 @@ static void host_main_loop_wait(int *tim
}
#endif
+static int cpu_has_work(CPUState *env)
+{
+ if (!env->halted)
+ return 1;
+ if (qemu_cpu_has_work(env))
+ return 1;
+ return 0;
+}
+
+static int tcg_has_work(CPUState *env)
+{
+ for (env = first_cpu; env != NULL; env = env->next_cpu)
+ if (cpu_has_work(env))
+ return 1;
+ return 0;
+}
+
+static void qemu_wait_io_event(CPUState *env, int timeout)
+{
+ if (timeout)
+ while (!tcg_has_work(env))
+ qemu_cond_timedwait(&halt_cond, &qemu_global_mutex, timeout);
+
+ 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);
+
+ qemu_mutex_lock(&qemu_global_mutex);
+}
+
+void qemu_cpu_kick(void *env)
+{
+ qemu_cond_broadcast(&halt_cond);
+}
+
+int qemu_cpu_self(void *env)
+{
+ return (cpu_single_env != NULL);
+}
+
+static void cpu_signal(int sig)
+{
+ if (cpu_single_env)
+ cpu_exit(cpu_single_env);
+}
+
+static void block_io_signals(void)
+{
+ sigset_t set;
+ struct sigaction sigact;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = cpu_signal;
+ sigaction(SIGUSR1, &sigact, NULL);
+}
+
+static void unblock_io_signals(void)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+}
+
+static void qemu_signal_lock(unsigned int msecs)
+{
+ qemu_mutex_lock(&qemu_fair_mutex);
+
+ while (qemu_mutex_trylock(&qemu_global_mutex)) {
+ qemu_thread_signal(&cpus_thread, SIGUSR1);
+ if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
+ break;
+ }
+ qemu_mutex_unlock(&qemu_fair_mutex);
+}
+
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh;
@@ -3775,7 +3872,14 @@ void main_loop_wait(int timeout)
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
}
#endif
+
+ /*
+ * main_loop_wait() *must* not assume any global state is consistent across
+ * select() invocations.
+ */
+ qemu_mutex_unlock(&qemu_global_mutex);
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+ qemu_signal_lock(100);
if (ret > 0) {
IOHandlerRecord **pioh;
@@ -3811,9 +3915,11 @@ void main_loop_wait(int timeout)
#endif
/* vm time timers */
- if (vm_running && likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
- qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
- qemu_get_clock(vm_clock));
+ if (vm_running) {
+ if (cur_cpu && likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
+ qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+ qemu_get_clock(vm_clock));
+ }
/* real time timers */
qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
@@ -3837,9 +3943,10 @@ static void setup_iothread_fd(void)
qemu_set_fd_handler2(fds[0], NULL, io_thread_wakeup, NULL,
(void *)(unsigned long)fds[0]);
io_thread_fd = fds[1];
+ fcntl(io_thread_fd, F_SETFL, O_NONBLOCK);
}
-static int main_loop(void)
+static void *cpu_main_loop(void *arg)
{
int ret, timeout;
#ifdef CONFIG_PROFILER
@@ -3847,7 +3954,12 @@ static int main_loop(void)
#endif
CPUState *env;
- cur_cpu = first_cpu;
+ block_io_signals();
+ qemu_thread_self(&cpus_thread);
+
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ cur_cpu = env = first_cpu;
next_cpu = cur_cpu->next_cpu ?: first_cpu;
for(;;) {
if (vm_running) {
@@ -3970,6 +4082,7 @@ static int main_loop(void)
timeout = 0;
}
} else {
+ env = env->next_cpu ?: first_cpu;
if (shutdown_requested) {
ret = EXCP_INTERRUPT;
break;
@@ -3979,13 +4092,31 @@ static int main_loop(void)
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
- main_loop_wait(timeout);
+ qemu_wait_io_event(env, timeout);
#ifdef CONFIG_PROFILER
dev_time += profile_getclock() - ti;
#endif
}
cpu_disable_ticks();
- return ret;
+ return NULL;
+}
+
+static void main_loop(void)
+{
+ qemu_cond_init(&halt_cond);
+ qemu_mutex_init(&qemu_fair_mutex);
+ qemu_mutex_init(&qemu_global_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ qemu_thread_self(&io_thread);
+ setup_iothread_fd();
+
+ unblock_io_signals();
+
+ qemu_thread_create(&cpus_thread, cpu_main_loop, NULL);
+
+ while (1)
+ main_loop_wait(1000);
}
static void help(int exitcode)
Index: trunk/exec.c
===================================================================
--- trunk.orig/exec.c
+++ trunk/exec.c
@@ -1532,6 +1532,13 @@ void cpu_interrupt(CPUState *env, int ma
old_mask = env->interrupt_request;
env->interrupt_request |= mask;
+#ifndef CONFIG_USER_ONLY
+ if (!qemu_cpu_self(env)) {
+ qemu_cpu_kick(env);
+ return;
+ }
+#endif
+
if (use_icount) {
env->icount_decr.u16.high = 0xffff;
#ifndef CONFIG_USER_ONLY
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 06/11] qemu: per-cpu thread information
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (4 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 05/11] qemu: separate thread for io Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 07/11] qemu: handle reset/poweroff/shutdown in iothread Marcelo Tosatti
` (4 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: percpu-state --]
[-- Type: text/plain, Size: 8651 bytes --]
Move per-cpu thread information to CPUState. Initialize through per-arch
cpu_init.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/cpu-defs.h
===================================================================
--- trunk.orig/cpu-defs.h
+++ trunk/cpu-defs.h
@@ -158,6 +158,8 @@ typedef struct CPUWatchpoint {
TAILQ_ENTRY(CPUWatchpoint) entry;
} CPUWatchpoint;
+#include "qemu-thread.h"
+
#define CPU_TEMP_BUF_NLONGS 128
#define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \
@@ -209,6 +211,9 @@ typedef struct CPUWatchpoint {
/* user data */ \
void *opaque; \
\
+ uint32_t created; \
+ struct QemuThread *thread; \
+ struct QemuCond *halt_cond; \
const char *cpu_model_str; \
struct KVMState *kvm_state; \
struct kvm_run *kvm_run; \
Index: trunk/target-i386/helper.c
===================================================================
--- trunk.orig/target-i386/helper.c
+++ trunk/target-i386/helper.c
@@ -1670,5 +1670,8 @@ CPUX86State *cpu_x86_init(const char *cp
#endif
if (kvm_enabled())
kvm_init_vcpu(env);
+
+ qemu_init_vcpu(env);
+
return env;
}
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -283,8 +283,15 @@ QemuMutex qemu_global_mutex;
QemuMutex qemu_fair_mutex;
QemuThread io_thread;
-QemuThread cpus_thread;
-QemuCond halt_cond;
+
+QemuThread *tcg_cpu_thread;
+QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+QemuCond qemu_cpu_cond;
+/* system init */
+QemuCond qemu_system_cond;
/***********************************************************/
/* x86 ISA bus support */
@@ -3752,7 +3759,7 @@ static void qemu_wait_io_event(CPUState
{
if (timeout)
while (!tcg_has_work(env))
- qemu_cond_timedwait(&halt_cond, &qemu_global_mutex, timeout);
+ qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, timeout);
qemu_mutex_unlock(&qemu_global_mutex);
@@ -3767,9 +3774,10 @@ static void qemu_wait_io_event(CPUState
qemu_mutex_lock(&qemu_global_mutex);
}
-void qemu_cpu_kick(void *env)
+void qemu_cpu_kick(void *_env)
{
- qemu_cond_broadcast(&halt_cond);
+ CPUState *env = _env;
+ qemu_cond_broadcast(env->halt_cond);
}
int qemu_cpu_self(void *env)
@@ -3823,7 +3831,7 @@ static void qemu_signal_lock(unsigned in
qemu_mutex_lock(&qemu_fair_mutex);
while (qemu_mutex_trylock(&qemu_global_mutex)) {
- qemu_thread_signal(&cpus_thread, SIGUSR1);
+ qemu_thread_signal(tcg_cpu_thread, SIGUSR1);
if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
break;
}
@@ -3952,12 +3960,19 @@ static void *cpu_main_loop(void *arg)
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
- CPUState *env;
+ CPUState *env = arg;
block_io_signals();
- qemu_thread_self(&cpus_thread);
+ qemu_thread_self(env->thread);
+ /* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
+ 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);
cur_cpu = env = first_cpu;
next_cpu = cur_cpu->next_cpu ?: first_cpu;
@@ -4101,19 +4116,41 @@ static void *cpu_main_loop(void *arg)
return NULL;
}
-static void main_loop(void)
+void qemu_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, cpu_main_loop, env);
+ 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 {
+ env->thread = tcg_cpu_thread;
+ env->halt_cond = tcg_halt_cond;
+ }
+}
+
+static void qemu_init_state(void)
{
- qemu_cond_init(&halt_cond);
qemu_mutex_init(&qemu_fair_mutex);
qemu_mutex_init(&qemu_global_mutex);
qemu_mutex_lock(&qemu_global_mutex);
+}
+static void main_loop(void)
+{
qemu_thread_self(&io_thread);
setup_iothread_fd();
unblock_io_signals();
- qemu_thread_create(&cpus_thread, cpu_main_loop, NULL);
+ qemu_system_ready = 1;
+ qemu_cond_broadcast(&qemu_system_cond);
while (1)
main_loop_wait(1000);
@@ -5213,6 +5250,7 @@ int main(int argc, char **argv, char **e
if (smp_cpus > 1)
kqemu_allowed = 0;
#endif
+ qemu_init_state();
linux_boot = (kernel_filename != NULL);
net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
Index: trunk/qemu-common.h
===================================================================
--- trunk.orig/qemu-common.h
+++ trunk/qemu-common.h
@@ -195,6 +195,12 @@ void qemu_notify_event(void);
void qemu_cpu_kick(void *env);
int qemu_cpu_self(void *env);
+#ifdef CONFIG_USER_ONLY
+#define qemu_init_vcpu(env) do { } while (0)
+#else
+void qemu_init_vcpu(void *env);
+#endif
+
typedef struct QEMUIOVector {
struct iovec *iov;
int niov;
Index: trunk/target-arm/helper.c
===================================================================
--- trunk.orig/target-arm/helper.c
+++ trunk/target-arm/helper.c
@@ -267,6 +267,7 @@ CPUARMState *cpu_arm_init(const char *cp
gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
19, "arm-vfp.xml", 0);
}
+ qemu_init_vcpu(env);
return env;
}
Index: trunk/target-m68k/helper.c
===================================================================
--- trunk.orig/target-m68k/helper.c
+++ trunk/target-m68k/helper.c
@@ -180,6 +180,7 @@ CPUM68KState *cpu_m68k_init(const char *
}
cpu_reset(env);
+ qemu_init_vcpu(env);
return env;
}
Index: trunk/target-ppc/helper.c
===================================================================
--- trunk.orig/target-ppc/helper.c
+++ trunk/target-ppc/helper.c
@@ -2833,6 +2833,7 @@ CPUPPCState *cpu_ppc_init (const char *c
if (kvm_enabled())
kvm_init_vcpu(env);
+ qemu_init_vcpu(env);
return env;
}
Index: trunk/target-sparc/helper.c
===================================================================
--- trunk.orig/target-sparc/helper.c
+++ trunk/target-sparc/helper.c
@@ -723,6 +723,7 @@ CPUSPARCState *cpu_sparc_init(const char
return NULL;
}
cpu_reset(env);
+ qemu_init_vcpu(env);
return env;
}
Index: trunk/target-alpha/translate.c
===================================================================
--- trunk.orig/target-alpha/translate.c
+++ trunk/target-alpha/translate.c
@@ -2494,6 +2494,7 @@ CPUAlphaState * cpu_alpha_init (const ch
env->ipr[IPR_SISR] = 0;
env->ipr[IPR_VIRBND] = -1ULL;
+ qemu_init_vcpu(env);
return env;
}
Index: trunk/target-cris/translate.c
===================================================================
--- trunk.orig/target-cris/translate.c
+++ trunk/target-cris/translate.c
@@ -3404,6 +3404,7 @@ CPUCRISState *cpu_cris_init (const char
cpu_exec_init(env);
cpu_reset(env);
+ qemu_init_vcpu(env);
if (tcg_initialized)
return env;
Index: trunk/target-mips/translate.c
===================================================================
--- trunk.orig/target-mips/translate.c
+++ trunk/target-mips/translate.c
@@ -8366,6 +8366,7 @@ CPUMIPSState *cpu_mips_init (const char
env->cpu_model_str = cpu_model;
mips_tcg_init();
cpu_reset(env);
+ qemu_init_vcpu(env);
return env;
}
Index: trunk/target-sh4/translate.c
===================================================================
--- trunk.orig/target-sh4/translate.c
+++ trunk/target-sh4/translate.c
@@ -290,6 +290,7 @@ CPUSH4State *cpu_sh4_init(const char *cp
cpu_sh4_reset(env);
cpu_sh4_register(env, def);
tlb_flush(env, 1);
+ qemu_init_vcpu(env);
return env;
}
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 07/11] qemu: handle reset/poweroff/shutdown in iothread
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (5 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 06/11] qemu: per-cpu thread information Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 08/11] qemu: pause and resume cpu threads Marcelo Tosatti
` (3 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: move-machine-events-to-iothread-2 --]
[-- Type: text/plain, Size: 1943 bytes --]
Its simpler to handle these events from only one context.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -4031,25 +4031,6 @@ static void *cpu_main_loop(void *arg)
}
cur_cpu = env;
- if (shutdown_requested) {
- ret = EXCP_INTERRUPT;
- if (no_shutdown) {
- vm_stop(0);
- no_shutdown = 0;
- }
- else
- break;
- }
- if (reset_requested) {
- reset_requested = 0;
- qemu_system_reset();
- ret = EXCP_INTERRUPT;
- }
- if (powerdown_requested) {
- powerdown_requested = 0;
- qemu_system_powerdown();
- ret = EXCP_INTERRUPT;
- }
if (unlikely(ret == EXCP_DEBUG)) {
gdb_set_stop_cpu(cur_cpu);
vm_stop(EXCP_DEBUG);
@@ -4098,10 +4079,6 @@ static void *cpu_main_loop(void *arg)
}
} else {
env = env->next_cpu ?: first_cpu;
- if (shutdown_requested) {
- ret = EXCP_INTERRUPT;
- break;
- }
timeout = 5000;
}
#ifdef CONFIG_PROFILER
@@ -4152,8 +4129,18 @@ static void main_loop(void)
qemu_system_ready = 1;
qemu_cond_broadcast(&qemu_system_cond);
- while (1)
+ while (1) {
main_loop_wait(1000);
+ if (qemu_shutdown_requested()) {
+ if (no_shutdown)
+ no_shutdown = 0;
+ else
+ break;
+ } else if (qemu_powerdown_requested())
+ qemu_system_powerdown();
+ else if (qemu_reset_requested())
+ qemu_system_reset();
+ }
}
static void help(int exitcode)
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 08/11] qemu: pause and resume cpu threads
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (6 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 07/11] qemu: handle reset/poweroff/shutdown in iothread Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 09/11] qemu: handle vmstop from cpu context Marcelo Tosatti
` (2 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: pause-stop-threads-2 --]
[-- Type: text/plain, Size: 5283 bytes --]
Since cpu emulation happens on a separate thread, it is necessary to
pause/resume it upon certain events such as reset, debug exception,
live migration, etc.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/cpu-defs.h
===================================================================
--- trunk.orig/cpu-defs.h
+++ trunk/cpu-defs.h
@@ -172,6 +172,8 @@ typedef struct CPUWatchpoint {
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
+ uint32_t stop; /* Stop request */ \
+ uint32_t stopped; /* Artificially stopped */ \
uint32_t interrupt_request; \
volatile sig_atomic_t exit_request; \
/* The meaning of the MMU modes is defined in the target code. */ \
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -293,6 +293,11 @@ QemuCond qemu_cpu_cond;
/* system init */
QemuCond qemu_system_cond;
+QemuCond qemu_pause_cond;
+
+static void pause_all_vcpus(void);
+static void resume_all_vcpus(void);
+
/***********************************************************/
/* x86 ISA bus support */
@@ -3540,6 +3545,7 @@ void vm_start(void)
if (!vm_running) {
cpu_enable_ticks();
vm_running = 1;
+ resume_all_vcpus();
vm_state_notify(1, 0);
qemu_rearm_alarm_timer(alarm_timer);
}
@@ -3550,6 +3556,7 @@ void vm_stop(int reason)
if (vm_running) {
cpu_disable_ticks();
vm_running = 0;
+ pause_all_vcpus();
vm_state_notify(0, reason);
}
}
@@ -3738,8 +3745,29 @@ static void host_main_loop_wait(int *tim
}
#endif
+/* Q: is it allowed to enter cpu_exec */
+static int cpu_can_run(CPUState *env)
+{
+ if (env->stop)
+ return 0;
+ if (env->stopped)
+ return 0;
+ if (shutdown_requested)
+ return 0;
+ if (powerdown_requested)
+ return 0;
+ if (reset_requested)
+ return 0;
+ return 1;
+}
+
+/* Q: should break out of the wait loop */
static int cpu_has_work(CPUState *env)
{
+ if (env->stop)
+ return 1;
+ if (env->stopped)
+ return 0;
if (!env->halted)
return 1;
if (qemu_cpu_has_work(env))
@@ -3772,6 +3800,11 @@ static void qemu_wait_io_event(CPUState
qemu_mutex_unlock(&qemu_fair_mutex);
qemu_mutex_lock(&qemu_global_mutex);
+ if (env->stop) {
+ env->stop = 0;
+ env->stopped = 1;
+ qemu_cond_signal(&qemu_pause_cond);
+ }
}
void qemu_cpu_kick(void *_env)
@@ -3838,6 +3871,53 @@ static void qemu_signal_lock(unsigned in
qemu_mutex_unlock(&qemu_fair_mutex);
}
+static int all_vcpus_paused(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ if (penv->stop)
+ return 0;
+ penv = (CPUState *)penv->next_cpu;
+ }
+
+ return 1;
+}
+
+static void pause_all_vcpus(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ penv->stop = 1;
+ qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_cpu_kick(penv);
+ penv = (CPUState *)penv->next_cpu;
+ }
+
+ while (!all_vcpus_paused()) {
+ qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
+ penv = first_cpu;
+ while (penv) {
+ qemu_thread_signal(penv->thread, SIGUSR1);
+ penv = (CPUState *)penv->next_cpu;
+ }
+ }
+}
+
+static void resume_all_vcpus(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ penv->stop = 0;
+ penv->stopped = 0;
+ qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_cpu_kick(penv);
+ penv = (CPUState *)penv->next_cpu;
+ }
+}
+
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh;
@@ -4000,7 +4080,9 @@ static void *cpu_main_loop(void *arg)
env->icount_decr.u16.low = decr;
env->icount_extra = count;
}
- ret = cpu_exec(env);
+ ret = EXCP_HALTED;
+ if (cpu_can_run(env))
+ ret = cpu_exec(env);
#ifdef CONFIG_PROFILER
qemu_time += profile_getclock() - ti;
#endif
@@ -4114,6 +4196,7 @@ void qemu_init_vcpu(void *_env)
static void qemu_init_state(void)
{
+ qemu_cond_init(&qemu_pause_cond);
qemu_mutex_init(&qemu_fair_mutex);
qemu_mutex_init(&qemu_global_mutex);
qemu_mutex_lock(&qemu_global_mutex);
@@ -4132,14 +4215,18 @@ static void main_loop(void)
while (1) {
main_loop_wait(1000);
if (qemu_shutdown_requested()) {
+ pause_all_vcpus();
if (no_shutdown)
no_shutdown = 0;
else
break;
} else if (qemu_powerdown_requested())
qemu_system_powerdown();
- else if (qemu_reset_requested())
+ else if (qemu_reset_requested()) {
+ pause_all_vcpus();
qemu_system_reset();
+ resume_all_vcpus();
+ }
}
}
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 09/11] qemu: handle vmstop from cpu context
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (7 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 08/11] qemu: pause and resume cpu threads Marcelo Tosatti
@ 2009-04-02 23:32 ` Marcelo Tosatti
2009-04-06 18:06 ` Anthony Liguori
2009-04-02 23:33 ` [Qemu-devel] [patch 10/11] qemu: make iothread selectable at compile time Marcelo Tosatti
2009-04-02 23:33 ` [Qemu-devel] [patch 11/11] qemu: basic kvm iothread support Marcelo Tosatti
10 siblings, 1 reply; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: handle-vmstop-vcpu --]
[-- Type: text/plain, Size: 2308 bytes --]
There are certain cases where cpu context requests a vm stop, such as
-ENOSPC handling.
IMO its simpler to handle vmstop only through the iothread.
Note there is change in behaviour: now the cpu thread which requested vm_stop
will actually only stop when it exits back to cpu_main_loop. It might cause
further damage in between vmstop and cpu_main_loop.
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -3551,7 +3551,22 @@ void vm_start(void)
}
}
-void vm_stop(int reason)
+static int vmstop_requested;
+
+static int qemu_vmstop_requested(void)
+{
+ int r = vmstop_requested;
+ vmstop_requested = 0;
+ return r;
+}
+
+static void qemu_system_vmstop_request(int reason)
+{
+ vmstop_requested = reason;
+ main_loop_break();
+}
+
+static void __vm_stop(int reason)
{
if (vm_running) {
cpu_disable_ticks();
@@ -3561,6 +3576,21 @@ void vm_stop(int reason)
}
}
+void vm_stop(int reason)
+{
+ QemuThread me;
+ qemu_thread_self(&me);
+
+ if (!qemu_thread_equal(&me, &io_thread)) {
+ qemu_system_vmstop_request(reason);
+ /* make sure we can't return to cpu_exec */
+ if (cpu_single_env)
+ cpu_single_env->stop = 1;
+ return;
+ }
+ __vm_stop(reason);
+}
+
/* reset/shutdown handler */
typedef struct QEMUResetEntry {
@@ -3758,6 +3788,8 @@ static int cpu_can_run(CPUState *env)
return 0;
if (reset_requested)
return 0;
+ if (vmstop_requested)
+ return 0;
return 1;
}
@@ -4204,6 +4236,8 @@ static void qemu_init_state(void)
static void main_loop(void)
{
+ int r;
+
qemu_thread_self(&io_thread);
setup_iothread_fd();
@@ -4220,12 +4254,14 @@ static void main_loop(void)
no_shutdown = 0;
else
break;
- } else if (qemu_powerdown_requested())
+ } else if (qemu_powerdown_requested()) {
qemu_system_powerdown();
- else if (qemu_reset_requested()) {
+ } else if (qemu_reset_requested()) {
pause_all_vcpus();
qemu_system_reset();
resume_all_vcpus();
+ } else if ((r = qemu_vmstop_requested())) {
+ vm_stop(r);
}
}
}
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [patch 09/11] qemu: handle vmstop from cpu context
2009-04-02 23:32 ` [Qemu-devel] [patch 09/11] qemu: handle vmstop from cpu context Marcelo Tosatti
@ 2009-04-06 18:06 ` Anthony Liguori
0 siblings, 0 replies; 16+ messages in thread
From: Anthony Liguori @ 2009-04-06 18:06 UTC (permalink / raw)
To: qemu-devel
Marcelo Tosatti wrote:
> There are certain cases where cpu context requests a vm stop, such as
> -ENOSPC handling.
>
> IMO its simpler to handle vmstop only through the iothread.
>
> Note there is change in behaviour: now the cpu thread which requested vm_stop
> will actually only stop when it exits back to cpu_main_loop. It might cause
> further damage in between vmstop and cpu_main_loop.
>
Missing SoB line.
Regards,
Anthony Liguori
> Index: trunk/vl.c
> ===================================================================
> --- trunk.orig/vl.c
> +++ trunk/vl.c
> @@ -3551,7 +3551,22 @@ void vm_start(void)
> }
> }
>
> -void vm_stop(int reason)
> +static int vmstop_requested;
> +
> +static int qemu_vmstop_requested(void)
> +{
> + int r = vmstop_requested;
> + vmstop_requested = 0;
> + return r;
> +}
> +
> +static void qemu_system_vmstop_request(int reason)
> +{
> + vmstop_requested = reason;
> + main_loop_break();
> +}
> +
> +static void __vm_stop(int reason)
> {
> if (vm_running) {
> cpu_disable_ticks();
> @@ -3561,6 +3576,21 @@ void vm_stop(int reason)
> }
> }
>
> +void vm_stop(int reason)
> +{
> + QemuThread me;
> + qemu_thread_self(&me);
> +
> + if (!qemu_thread_equal(&me, &io_thread)) {
> + qemu_system_vmstop_request(reason);
> + /* make sure we can't return to cpu_exec */
> + if (cpu_single_env)
> + cpu_single_env->stop = 1;
> + return;
> + }
> + __vm_stop(reason);
> +}
> +
> /* reset/shutdown handler */
>
> typedef struct QEMUResetEntry {
> @@ -3758,6 +3788,8 @@ static int cpu_can_run(CPUState *env)
> return 0;
> if (reset_requested)
> return 0;
> + if (vmstop_requested)
> + return 0;
> return 1;
> }
>
> @@ -4204,6 +4236,8 @@ static void qemu_init_state(void)
>
> static void main_loop(void)
> {
> + int r;
> +
> qemu_thread_self(&io_thread);
> setup_iothread_fd();
>
> @@ -4220,12 +4254,14 @@ static void main_loop(void)
> no_shutdown = 0;
> else
> break;
> - } else if (qemu_powerdown_requested())
> + } else if (qemu_powerdown_requested()) {
> qemu_system_powerdown();
> - else if (qemu_reset_requested()) {
> + } else if (qemu_reset_requested()) {
> pause_all_vcpus();
> qemu_system_reset();
> resume_all_vcpus();
> + } else if ((r = qemu_vmstop_requested())) {
> + vm_stop(r);
> }
> }
> }
>
>
--
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 10/11] qemu: make iothread selectable at compile time
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (8 preceding siblings ...)
2009-04-02 23:32 ` [Qemu-devel] [patch 09/11] qemu: handle vmstop from cpu context Marcelo Tosatti
@ 2009-04-02 23:33 ` Marcelo Tosatti
2009-04-02 23:33 ` [Qemu-devel] [patch 11/11] qemu: basic kvm iothread support Marcelo Tosatti
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:33 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: optimize-tcg --]
[-- Type: text/plain, Size: 19685 bytes --]
Turned off by default.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -277,6 +277,7 @@ static QEMUTimer *nographic_timer;
uint8_t qemu_uuid[16];
+#ifdef QEMU_THREADED
static int io_thread_fd = -1;
QemuMutex qemu_global_mutex;
@@ -294,6 +295,7 @@ QemuCond qemu_cpu_cond;
QemuCond qemu_system_cond;
QemuCond qemu_pause_cond;
+#endif
static void pause_all_vcpus(void);
static void resume_all_vcpus(void);
@@ -1367,6 +1369,14 @@ static void host_alarm_handler(int host_
write(alarm_timer_wfd, &byte, sizeof(byte));
#endif
alarm_timer->flags |= ALARM_FLAG_EXPIRED;
+#ifndef QEMU_THREADED
+ {
+ CPUState *env = next_cpu;
+ if (env)
+ cpu_exit(env);
+ event_pending = 1;
+ }
+#endif
}
}
@@ -3343,6 +3353,7 @@ static int ram_load(QEMUFile *f, void *o
void qemu_service_io(void)
{
+ qemu_notify_event();
}
/***********************************************************/
@@ -3560,11 +3571,13 @@ static int qemu_vmstop_requested(void)
return r;
}
+#ifdef QEMU_THREADED
static void qemu_system_vmstop_request(int reason)
{
vmstop_requested = reason;
main_loop_break();
}
+#endif
static void __vm_stop(int reason)
{
@@ -3578,6 +3591,7 @@ static void __vm_stop(int reason)
void vm_stop(int reason)
{
+#ifdef QEMU_THREADED
QemuThread me;
qemu_thread_self(&me);
@@ -3588,6 +3602,7 @@ void vm_stop(int reason)
cpu_single_env->stop = 1;
return;
}
+#endif
__vm_stop(reason);
}
@@ -3671,6 +3686,7 @@ void qemu_system_powerdown_request(void)
main_loop_break();
}
+#ifdef QEMU_THREADED
void qemu_notify_event(void)
{
main_loop_break();
@@ -3725,74 +3741,6 @@ static void io_thread_wakeup(void *opaqu
}
}
-#ifdef _WIN32
-static void host_main_loop_wait(int *timeout)
-{
- int ret, ret2, i;
- PollingEntry *pe;
-
-
- /* XXX: need to suppress polling by better using win32 events */
- ret = 0;
- for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
- ret |= pe->func(pe->opaque);
- }
- if (ret == 0) {
- int err;
- WaitObjects *w = &wait_objects;
-
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0])
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
- /* Check for additional signaled events */
- for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if(ret2 == WAIT_OBJECT_0) {
- if (w->func[i])
- w->func[i](w->opaque[i]);
- } else if (ret2 == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
- }
- }
- } else if (ret == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
- }
- }
-
- *timeout = 0;
-}
-#else
-static void host_main_loop_wait(int *timeout)
-{
-}
-#endif
-
-/* Q: is it allowed to enter cpu_exec */
-static int cpu_can_run(CPUState *env)
-{
- if (env->stop)
- return 0;
- if (env->stopped)
- return 0;
- if (shutdown_requested)
- return 0;
- if (powerdown_requested)
- return 0;
- if (reset_requested)
- return 0;
- if (vmstop_requested)
- return 0;
- return 1;
-}
-
/* Q: should break out of the wait loop */
static int cpu_has_work(CPUState *env)
{
@@ -3950,6 +3898,187 @@ static void resume_all_vcpus(void)
}
}
+static void *cpu_thread(void *arg);
+
+void qemu_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, cpu_thread, env);
+ 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 {
+ env->thread = tcg_cpu_thread;
+ env->halt_cond = tcg_halt_cond;
+ }
+}
+
+static void qemu_init_state(void)
+{
+ qemu_cond_init(&qemu_pause_cond);
+ qemu_mutex_init(&qemu_fair_mutex);
+ qemu_mutex_init(&qemu_global_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+}
+
+static void setup_iothread_fd(void);
+static void pre_main_loop(void)
+{
+ qemu_thread_self(&io_thread);
+ setup_iothread_fd();
+
+ unblock_io_signals();
+
+ qemu_system_ready = 1;
+ qemu_cond_broadcast(&qemu_system_cond);
+}
+
+static int qemu_cpu_exec(CPUState *env);
+static void *cpu_thread(void *arg)
+{
+ int r;
+ CPUState *env = arg;
+
+ block_io_signals();
+ qemu_thread_self(env->thread);
+
+ /* signal CPU creation */
+ qemu_mutex_lock(&qemu_global_mutex);
+ 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 (1) {
+ r = qemu_cpu_exec(env);
+ qemu_wait_io_event(env, r);
+ }
+
+ return NULL;
+}
+
+static void setup_iothread_fd(void)
+{
+ int fds[2];
+
+ if (pipe(fds) == -1) {
+ fprintf(stderr, "failed to create iothread pipe");
+ exit(0);
+ }
+
+ qemu_set_fd_handler2(fds[0], NULL, io_thread_wakeup, NULL,
+ (void *)(unsigned long)fds[0]);
+ io_thread_fd = fds[1];
+ fcntl(io_thread_fd, F_SETFL, O_NONBLOCK);
+}
+
+#else /* QEMU_THREADED */
+#define qemu_signal_lock(a) do { } while(0)
+#define qemu_mutex_unlock(a) do { } while(0)
+#define pre_main_loop() do { } while(0)
+#define qemu_init_state() do { } while(0)
+
+void pause_all_vcpus(void)
+{
+ return;
+}
+
+void resume_all_vcpus(void)
+{
+ return;
+}
+
+void qemu_cpu_kick(void *env)
+{
+ return;
+}
+
+void qemu_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+
+ if (kvm_enabled())
+ kvm_init_vcpu(env);
+ return;
+}
+
+void qemu_notify_event(void)
+{
+ CPUState *env = cpu_single_env;
+
+ if (env)
+ cpu_exit(env);
+}
+
+void main_loop_break(void)
+{
+ qemu_notify_event();
+}
+
+int qemu_cpu_self(void *env)
+{
+ return 1;
+}
+#endif
+
+#ifdef _WIN32
+static void host_main_loop_wait(int *timeout)
+{
+ int ret, ret2, i;
+ PollingEntry *pe;
+
+
+ /* XXX: need to suppress polling by better using win32 events */
+ ret = 0;
+ for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
+ ret |= pe->func(pe->opaque);
+ }
+ if (ret == 0) {
+ int err;
+ WaitObjects *w = &wait_objects;
+
+ ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+ if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+ if (w->func[ret - WAIT_OBJECT_0])
+ w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+
+ /* Check for additional signaled events */
+ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+ /* Check if event is signaled */
+ ret2 = WaitForSingleObject(w->events[i], 0);
+ if(ret2 == WAIT_OBJECT_0) {
+ if (w->func[i])
+ w->func[i](w->opaque[i]);
+ } else if (ret2 == WAIT_TIMEOUT) {
+ } else {
+ err = GetLastError();
+ fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+ }
+ }
+ } else if (ret == WAIT_TIMEOUT) {
+ } else {
+ err = GetLastError();
+ fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+ }
+ }
+
+ *timeout = 0;
+}
+#else
+static void host_main_loop_wait(int *timeout)
+{
+}
+#endif
+
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh;
@@ -4051,203 +4180,155 @@ void main_loop_wait(int timeout)
}
-static void setup_iothread_fd(void)
+/* Q: is it allowed to enter cpu_exec */
+static int cpu_can_run(CPUState *env)
{
- int fds[2];
-
- if (pipe(fds) == -1) {
- fprintf(stderr, "failed to create iothread pipe");
- exit(0);
- }
-
- qemu_set_fd_handler2(fds[0], NULL, io_thread_wakeup, NULL,
- (void *)(unsigned long)fds[0]);
- io_thread_fd = fds[1];
- fcntl(io_thread_fd, F_SETFL, O_NONBLOCK);
+ if (env->stop)
+ return 0;
+ if (env->stopped)
+ return 0;
+ if (shutdown_requested)
+ return 0;
+ if (powerdown_requested)
+ return 0;
+ if (reset_requested)
+ return 0;
+ if (vmstop_requested)
+ return 0;
+ return 1;
}
-static void *cpu_main_loop(void *arg)
+static int qemu_cpu_exec(CPUState *env)
{
int ret, timeout;
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
- CPUState *env = arg;
-
- block_io_signals();
- qemu_thread_self(env->thread);
-
- /* signal CPU creation */
- qemu_mutex_lock(&qemu_global_mutex);
- 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);
-
- cur_cpu = env = first_cpu;
- next_cpu = cur_cpu->next_cpu ?: first_cpu;
for(;;) {
- if (vm_running) {
-
- for(;;) {
- /* get next cpu */
- env = next_cpu;
+ /* get next cpu */
+ env = next_cpu;
#ifdef CONFIG_PROFILER
- ti = profile_getclock();
+ ti = profile_getclock();
#endif
- if (use_icount) {
- int64_t count;
- int decr;
- qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
- env->icount_decr.u16.low = 0;
- env->icount_extra = 0;
- count = qemu_next_deadline();
- count = (count + (1 << icount_time_shift) - 1)
- >> icount_time_shift;
- qemu_icount += count;
- decr = (count > 0xffff) ? 0xffff : count;
- count -= decr;
- env->icount_decr.u16.low = decr;
- env->icount_extra = count;
- }
- ret = EXCP_HALTED;
- if (cpu_can_run(env))
- ret = cpu_exec(env);
+ if (use_icount) {
+ int64_t count;
+ int decr;
+ qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
+ env->icount_decr.u16.low = 0;
+ env->icount_extra = 0;
+ count = qemu_next_deadline();
+ count = (count + (1 << icount_time_shift) - 1)
+ >> icount_time_shift;
+ qemu_icount += count;
+ decr = (count > 0xffff) ? 0xffff : count;
+ count -= decr;
+ env->icount_decr.u16.low = decr;
+ env->icount_extra = count;
+ }
+ ret = EXCP_HALTED;
+ if (cpu_can_run(env))
+ ret = cpu_exec(env);
#ifdef CONFIG_PROFILER
- qemu_time += profile_getclock() - ti;
+ qemu_time += profile_getclock() - ti;
#endif
- if (use_icount) {
- /* Fold pending instructions back into the
- instruction counter, and clear the interrupt flag. */
- qemu_icount -= (env->icount_decr.u16.low
- + env->icount_extra);
- env->icount_decr.u32 = 0;
- env->icount_extra = 0;
- }
- next_cpu = env->next_cpu ?: first_cpu;
- if (event_pending && likely(ret != EXCP_DEBUG)) {
- ret = EXCP_INTERRUPT;
- event_pending = 0;
- break;
- }
- if (ret == EXCP_HLT) {
- /* Give the next CPU a chance to run. */
- cur_cpu = env;
- continue;
- }
- if (ret != EXCP_HALTED)
- break;
- /* all CPUs are halted ? */
- if (env == cur_cpu)
- break;
- }
+ if (use_icount) {
+ /* Fold pending instructions back into the
+ instruction counter, and clear the interrupt flag. */
+ qemu_icount -= (env->icount_decr.u16.low
+ + env->icount_extra);
+ env->icount_decr.u32 = 0;
+ env->icount_extra = 0;
+ }
+ next_cpu = env->next_cpu ?: first_cpu;
+ if (event_pending && likely(ret != EXCP_DEBUG)) {
+ ret = EXCP_INTERRUPT;
+ event_pending = 0;
+ break;
+ }
+ if (ret == EXCP_HLT) {
+ /* Give the next CPU a chance to run. */
cur_cpu = env;
-
- if (unlikely(ret == EXCP_DEBUG)) {
- gdb_set_stop_cpu(cur_cpu);
- vm_stop(EXCP_DEBUG);
- }
- /* If all cpus are halted then wait until the next IRQ */
- /* XXX: use timeout computed from timers */
- if (ret == EXCP_HALTED) {
- if (use_icount) {
- int64_t add;
- int64_t delta;
- /* Advance virtual time to the next event. */
- if (use_icount == 1) {
- /* When not using an adaptive execution frequency
- we tend to get badly out of sync with real time,
- so just delay for a reasonable amount of time. */
- delta = 0;
- } else {
- delta = cpu_get_icount() - cpu_get_clock();
- }
- if (delta > 0) {
- /* If virtual time is ahead of real time then just
- wait for IO. */
- timeout = (delta / 1000000) + 1;
- } else {
- /* Wait for either IO to occur or the next
- timer event. */
- add = qemu_next_deadline();
- /* We advance the timer before checking for IO.
- Limit the amount we advance so that early IO
- activity won't get the guest too far ahead. */
- if (add > 10000000)
- add = 10000000;
- delta += add;
- add = (add + (1 << icount_time_shift) - 1)
- >> icount_time_shift;
- qemu_icount += add;
- timeout = delta / 1000000;
- if (timeout < 0)
- timeout = 0;
- }
- } else {
- timeout = 5000;
- }
- } else {
- timeout = 0;
- }
- } else {
- env = env->next_cpu ?: first_cpu;
- timeout = 5000;
+ continue;
}
+ if (ret != EXCP_HALTED)
+ break;
+ /* all CPUs are halted ? */
+ if (env == cur_cpu)
+ break;
+ }
+ cur_cpu = env;
+
+ if (unlikely(ret == EXCP_DEBUG)) {
+ gdb_set_stop_cpu(cur_cpu);
+ vm_stop(EXCP_DEBUG);
+ }
+ /* If all cpus are halted then wait until the next IRQ */
+ /* XXX: use timeout computed from timers */
+ if (ret == EXCP_HALTED) {
+ if (use_icount) {
+ int64_t add;
+ int64_t delta;
+ /* Advance virtual time to the next event. */
+ if (use_icount == 1) {
+ /* When not using an adaptive execution frequency
+ we tend to get badly out of sync with real time,
+ so just delay for a reasonable amount of time. */
+ delta = 0;
+ } else {
+ delta = cpu_get_icount() - cpu_get_clock();
+ }
+ if (delta > 0) {
+ /* If virtual time is ahead of real time then just
+ wait for IO. */
+ timeout = (delta / 1000000) + 1;
+ } else {
+ /* Wait for either IO to occur or the next
+ timer event. */
+ add = qemu_next_deadline();
+ /* We advance the timer before checking for IO.
+ Limit the amount we advance so that early IO
+ activity won't get the guest too far ahead. */
+ if (add > 10000000)
+ add = 10000000;
+ delta += add;
+ add = (add + (1 << icount_time_shift) - 1)
+ >> icount_time_shift;
+ qemu_icount += add;
+ timeout = delta / 1000000;
+ if (timeout < 0)
+ timeout = 0;
+ }
+ } else {
+ timeout = 5000;
+ }
+ } else {
+ timeout = 0;
+ }
#ifdef CONFIG_PROFILER
- ti = profile_getclock();
+ ti = profile_getclock();
#endif
- qemu_wait_io_event(env, timeout);
#ifdef CONFIG_PROFILER
- dev_time += profile_getclock() - ti;
+ dev_time += profile_getclock() - ti;
#endif
- }
- cpu_disable_ticks();
- return NULL;
-}
-
-void qemu_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, cpu_main_loop, env);
- 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 {
- env->thread = tcg_cpu_thread;
- env->halt_cond = tcg_halt_cond;
- }
-}
-
-static void qemu_init_state(void)
-{
- qemu_cond_init(&qemu_pause_cond);
- qemu_mutex_init(&qemu_fair_mutex);
- qemu_mutex_init(&qemu_global_mutex);
- qemu_mutex_lock(&qemu_global_mutex);
+ return timeout;
}
static void main_loop(void)
{
int r;
- qemu_thread_self(&io_thread);
- setup_iothread_fd();
-
- unblock_io_signals();
+ pre_main_loop();
- qemu_system_ready = 1;
- qemu_cond_broadcast(&qemu_system_cond);
+ cur_cpu = first_cpu;
+ next_cpu = cur_cpu->next_cpu ?: first_cpu;
while (1) {
+#ifdef QEMU_THREADED
main_loop_wait(1000);
+#else
+ r = qemu_cpu_exec(next_cpu);
+ main_loop_wait(r);
+#endif
if (qemu_shutdown_requested()) {
pause_all_vcpus();
if (no_shutdown)
--
^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [patch 11/11] qemu: basic kvm iothread support
2009-04-02 23:32 [Qemu-devel] [patch 00/11] iothread v2 Marcelo Tosatti
` (9 preceding siblings ...)
2009-04-02 23:33 ` [Qemu-devel] [patch 10/11] qemu: make iothread selectable at compile time Marcelo Tosatti
@ 2009-04-02 23:33 ` Marcelo Tosatti
10 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:33 UTC (permalink / raw)
To: qemu-devel; +Cc: Marcelo Tosatti
[-- Attachment #1: kvm --]
[-- Type: text/plain, Size: 4564 bytes --]
Allow the iothread to run while vcpu is in guest mode.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: trunk/kvm-all.c
===================================================================
--- trunk.orig/kvm-all.c
+++ trunk/kvm-all.c
@@ -451,6 +451,7 @@ int kvm_cpu_exec(CPUState *env)
do {
kvm_arch_pre_run(env, run);
+ kvm_pre_run(env);
if (env->exit_request) {
dprintf("interrupt exit requested\n");
@@ -459,6 +460,7 @@ int kvm_cpu_exec(CPUState *env)
}
ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
+ kvm_post_run(env);
kvm_arch_post_run(env, run);
if (ret == -EINTR || ret == -EAGAIN) {
Index: trunk/kvm.h
===================================================================
--- trunk.orig/kvm.h
+++ trunk/kvm.h
@@ -27,6 +27,10 @@ extern int kvm_allowed;
struct kvm_run;
+/* main loop interface, vl.c */
+void kvm_pre_run(CPUState *env);
+void kvm_post_run(CPUState *env);
+
/* external API */
int kvm_init(int smp_cpus);
Index: trunk/target-i386/helper.c
===================================================================
--- trunk.orig/target-i386/helper.c
+++ trunk/target-i386/helper.c
@@ -1668,9 +1668,6 @@ CPUX86State *cpu_x86_init(const char *cp
#ifdef USE_KQEMU
kqemu_init(env);
#endif
- if (kvm_enabled())
- kvm_init_vcpu(env);
-
qemu_init_vcpu(env);
return env;
Index: trunk/target-ppc/helper.c
===================================================================
--- trunk.orig/target-ppc/helper.c
+++ trunk/target-ppc/helper.c
@@ -2831,8 +2831,6 @@ CPUPPCState *cpu_ppc_init (const char *c
cpu_ppc_register_internal(env, def);
cpu_ppc_reset(env);
- if (kvm_enabled())
- kvm_init_vcpu(env);
qemu_init_vcpu(env);
return env;
Index: trunk/vl.c
===================================================================
--- trunk.orig/vl.c
+++ trunk/vl.c
@@ -3791,6 +3791,8 @@ void qemu_cpu_kick(void *_env)
{
CPUState *env = _env;
qemu_cond_broadcast(env->halt_cond);
+ if (kvm_enabled())
+ qemu_thread_signal(env->thread, SIGUSR1);
}
int qemu_cpu_self(void *env)
@@ -3851,6 +3853,16 @@ static void qemu_signal_lock(unsigned in
qemu_mutex_unlock(&qemu_fair_mutex);
}
+static void qemu_mutex_lock_iothread(void)
+{
+ if (kvm_enabled()) {
+ qemu_mutex_lock(&qemu_fair_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+ qemu_mutex_unlock(&qemu_fair_mutex);
+ } else
+ qemu_signal_lock(100);
+}
+
static int all_vcpus_paused(void)
{
CPUState *penv = first_cpu;
@@ -3900,7 +3912,7 @@ static void resume_all_vcpus(void)
static void *cpu_thread(void *arg);
-void qemu_init_vcpu(void *_env)
+static void tcg_init_vcpu(void *_env)
{
CPUState *env = _env;
/* share a single thread for all cpus with TCG */
@@ -3919,6 +3931,39 @@ void qemu_init_vcpu(void *_env)
}
}
+static void kvm_start_vcpu(CPUState *env)
+{
+ kvm_init_vcpu(env);
+ env->thread = qemu_mallocz(sizeof(QemuThread));
+ env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(env->thread, cpu_thread, env);
+ while (env->created == 0)
+ qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+}
+
+void kvm_pre_run(CPUState *env)
+{
+ cpu_single_env = NULL;
+ qemu_mutex_unlock(&qemu_global_mutex);
+}
+
+void kvm_post_run(CPUState *env)
+{
+ qemu_mutex_lock(&qemu_global_mutex);
+ cpu_single_env = env;
+}
+
+void qemu_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+
+ if (kvm_enabled())
+ kvm_start_vcpu(env);
+ else
+ tcg_init_vcpu(env);
+}
+
static void qemu_init_state(void)
{
qemu_cond_init(&qemu_pause_cond);
@@ -3985,6 +4030,7 @@ static void setup_iothread_fd(void)
#define qemu_mutex_unlock(a) do { } while(0)
#define pre_main_loop() do { } while(0)
#define qemu_init_state() do { } while(0)
+#define qemu_mutex_lock_iothread() do { } while(0)
void pause_all_vcpus(void)
{
@@ -4027,6 +4073,16 @@ int qemu_cpu_self(void *env)
{
return 1;
}
+
+void kvm_pre_run(CPUState *env)
+{
+ return;
+}
+
+void kvm_post_run(CPUState *env)
+{
+ return;
+}
#endif
#ifdef _WIN32
@@ -4128,7 +4184,7 @@ void main_loop_wait(int timeout)
*/
qemu_mutex_unlock(&qemu_global_mutex);
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
- qemu_signal_lock(100);
+ qemu_mutex_lock_iothread();
if (ret > 0) {
IOHandlerRecord **pioh;
--
^ permalink raw reply [flat|nested] 16+ messages in thread