All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.