qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [patch 00/11] iothread v2
@ 2009-04-02 23:32 Marcelo Tosatti
  2009-04-02 23:32 ` [Qemu-devel] [patch 01/11] qemu: create helper for event notification Marcelo Tosatti
                   ` (10 more replies)
  0 siblings, 11 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-04-02 23:32 UTC (permalink / raw)
  To: qemu-devel

Addressing comments from previous version.

-- 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [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

* [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

* [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

* 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

* 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

end of thread, other threads:[~2009-04-06 19:35 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-06 18:21   ` Anthony Liguori
2009-04-06 19:20     ` Marcelo Tosatti
2009-04-06 19:35       ` Anthony Liguori
2009-04-02 23:32 ` [Qemu-devel] [patch 03/11] qemu: per-arch cpu_has_work Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 04/11] qemu: introduce main_loop_break Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 05/11] qemu: separate thread for io Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 06/11] qemu: per-cpu thread information Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 07/11] qemu: handle reset/poweroff/shutdown in iothread Marcelo Tosatti
2009-04-02 23:32 ` [Qemu-devel] [patch 08/11] qemu: pause and resume cpu threads Marcelo Tosatti
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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).