Patchwork [RFC,v7,03/16] Make qemu timers available for tools

login
register
mail settings
Submitter Michael Roth
Date March 7, 2011, 8:10 p.m.
Message ID <1299528642-23631-4-git-send-email-mdroth@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/85810/
State New
Headers show

Comments

Michael Roth - March 7, 2011, 8:10 p.m.
To be able to use qemu_mod_timer() and friends to register timeout
events for virtagent's qemu-va tool, we need to do the following:

Move several blocks of code out of cpus.c that handle initialization
of qemu's io_thread_fd and working with it via
qemu_notify_event()/qemu_event_read()/etc, and make them accessible
as backend functions to both the emulator code and qemu-tool.c via
wrapper functions within cpus.c and qemu-tool.c, respectively. These
have been added to qemu-ioh.c, where similar treatment was given to
qemu_set_fd_handler() and friends.

Some of these wrapper functions lack declarations when being
built into tools, so we add those via qemu-tool.h, which can be included
by a tool to access them. With these changes we can drive timers in a
tool linking it against qemu-timer.o and then implementing something
similar to the main i/o loop in vl.c:

init_clocks();
configure_alarms("dynticks");
if (init_timer_alarm() < 0) {
    errx(EXIT_FAILURE, "could not initialize alarm timer");
}

while (running) {
    //do work
    qemu_run_all_timers();
}

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 cpus.c      |   83 +++++++--------------------------------------------
 qemu-ioh.c  |   95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-ioh.h  |    9 +++++
 qemu-tool.c |   92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 qemu-tool.h |   26 ++++++++++++++++
 5 files changed, 231 insertions(+), 74 deletions(-)
 create mode 100644 qemu-tool.h
Jes Sorensen - March 9, 2011, 10:33 a.m.
On 03/07/11 21:10, Michael Roth wrote:
> To be able to use qemu_mod_timer() and friends to register timeout
> events for virtagent's qemu-va tool, we need to do the following:
> 
> Move several blocks of code out of cpus.c that handle initialization
> of qemu's io_thread_fd and working with it via
> qemu_notify_event()/qemu_event_read()/etc, and make them accessible
> as backend functions to both the emulator code and qemu-tool.c via
> wrapper functions within cpus.c and qemu-tool.c, respectively. These
> have been added to qemu-ioh.c, where similar treatment was given to
> qemu_set_fd_handler() and friends.
> 
> Some of these wrapper functions lack declarations when being
> built into tools, so we add those via qemu-tool.h, which can be included
> by a tool to access them. With these changes we can drive timers in a
> tool linking it against qemu-timer.o and then implementing something
> similar to the main i/o loop in vl.c:
> 

[snip]

> diff --git a/qemu-ioh.c b/qemu-ioh.c
> index cc71470..5c3f94c 100644
> --- a/qemu-ioh.c
> +++ b/qemu-ioh.c
> @@ -113,3 +117,94 @@ void qemu_process_fd_handlers2(void *ioh_record_list, const fd_set *rfds,
>          }
>      }
>  }
> +
> +#ifndef _WIN32
> +void iothread_event_increment(int *io_thread_fd)

Please move these functions into posix/w32 specific files so we don't
get anymore ugly #ifdefs. It would be good if we could use a wrapper
struct as well to hide the different data types so we don't need #ifdefs
in the calling code as well.

Cheers,
Jes
Michael Roth - March 9, 2011, 1:04 p.m.
On 03/09/2011 04:33 AM, Jes Sorensen wrote:
> On 03/07/11 21:10, Michael Roth wrote:
>> To be able to use qemu_mod_timer() and friends to register timeout
>> events for virtagent's qemu-va tool, we need to do the following:
>>
>> Move several blocks of code out of cpus.c that handle initialization
>> of qemu's io_thread_fd and working with it via
>> qemu_notify_event()/qemu_event_read()/etc, and make them accessible
>> as backend functions to both the emulator code and qemu-tool.c via
>> wrapper functions within cpus.c and qemu-tool.c, respectively. These
>> have been added to qemu-ioh.c, where similar treatment was given to
>> qemu_set_fd_handler() and friends.
>>
>> Some of these wrapper functions lack declarations when being
>> built into tools, so we add those via qemu-tool.h, which can be included
>> by a tool to access them. With these changes we can drive timers in a
>> tool linking it against qemu-timer.o and then implementing something
>> similar to the main i/o loop in vl.c:
>>
>
> [snip]
>
>> diff --git a/qemu-ioh.c b/qemu-ioh.c
>> index cc71470..5c3f94c 100644
>> --- a/qemu-ioh.c
>> +++ b/qemu-ioh.c
>> @@ -113,3 +117,94 @@ void qemu_process_fd_handlers2(void *ioh_record_list, const fd_set *rfds,
>>           }
>>       }
>>   }
>> +
>> +#ifndef _WIN32
>> +void iothread_event_increment(int *io_thread_fd)
>
> Please move these functions into posix/w32 specific files so we don't
> get anymore ugly #ifdefs. It would be good if we could use a wrapper
> struct as well to hide the different data types so we don't need #ifdefs
> in the calling code as well.

Yup, meant to add this to the TODO. I may end up sending these general 
tools changes out in a separate patchset since they seem to be in 
conflict with quite of few patches floating around the list. Either way 
I'll make sure to get these cleaned up and tested a bit a more.

>
> Cheers,
> Jes
>
Jes Sorensen - March 9, 2011, 1:06 p.m.
On 03/09/11 14:04, Michael Roth wrote:
> On 03/09/2011 04:33 AM, Jes Sorensen wrote:
>>> diff --git a/qemu-ioh.c b/qemu-ioh.c
>>> index cc71470..5c3f94c 100644
>>> --- a/qemu-ioh.c
>>> +++ b/qemu-ioh.c
>>> @@ -113,3 +117,94 @@ void qemu_process_fd_handlers2(void
>>> *ioh_record_list, const fd_set *rfds,
>>>           }
>>>       }
>>>   }
>>> +
>>> +#ifndef _WIN32
>>> +void iothread_event_increment(int *io_thread_fd)
>>
>> Please move these functions into posix/w32 specific files so we don't
>> get anymore ugly #ifdefs. It would be good if we could use a wrapper
>> struct as well to hide the different data types so we don't need #ifdefs
>> in the calling code as well.
> 
> Yup, meant to add this to the TODO. I may end up sending these general
> tools changes out in a separate patchset since they seem to be in
> conflict with quite of few patches floating around the list. Either way
> I'll make sure to get these cleaned up and tested a bit a more.

Sounds great! Since they are not directly part of virtagent you should
be able to push them in soon too.

Cheers,
Jes

Patch

diff --git a/cpus.c b/cpus.c
index 0f33945..507a660 100644
--- a/cpus.c
+++ b/cpus.c
@@ -246,64 +246,12 @@  static int io_thread_fd = -1;
 
 static void qemu_event_increment(void)
 {
-    /* Write 8 bytes to be compatible with eventfd.  */
-    static const uint64_t val = 1;
-    ssize_t ret;
-
-    if (io_thread_fd == -1) {
-        return;
-    }
-    do {
-        ret = write(io_thread_fd, &val, sizeof(val));
-    } while (ret < 0 && errno == EINTR);
-
-    /* EAGAIN is fine, a read must be pending.  */
-    if (ret < 0 && errno != EAGAIN) {
-        fprintf(stderr, "qemu_event_increment: write() filed: %s\n",
-                strerror(errno));
-        exit (1);
-    }
-}
-
-static void qemu_event_read(void *opaque)
-{
-    int fd = (unsigned long)opaque;
-    ssize_t len;
-    char buffer[512];
-
-    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
-    do {
-        len = read(fd, buffer, sizeof(buffer));
-    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+    return iothread_event_increment(&io_thread_fd);
 }
 
 static int qemu_event_init(void)
 {
-    int err;
-    int fds[2];
-
-    err = qemu_eventfd(fds);
-    if (err == -1) {
-        return -errno;
-    }
-    err = fcntl_setfl(fds[0], O_NONBLOCK);
-    if (err < 0) {
-        goto fail;
-    }
-    err = fcntl_setfl(fds[1], O_NONBLOCK);
-    if (err < 0) {
-        goto fail;
-    }
-    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
-                         (void *)(unsigned long)fds[0]);
-
-    io_thread_fd = fds[1];
-    return 0;
-
-fail:
-    close(fds[0]);
-    close(fds[1]);
-    return err;
+    return iothread_event_init(&io_thread_fd);
 }
 
 static void dummy_signal(int sig)
@@ -410,28 +358,14 @@  static void qemu_kvm_eat_signals(CPUState *env)
 
 HANDLE qemu_event_handle;
 
-static void dummy_event_handler(void *opaque)
-{
-}
-
 static int qemu_event_init(void)
 {
-    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!qemu_event_handle) {
-        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
-        return -1;
-    }
-    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
-    return 0;
+    return win32_event_init(&qemu_event_handle);
 }
 
 static void qemu_event_increment(void)
 {
-    if (!SetEvent(qemu_event_handle)) {
-        fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
-                GetLastError());
-        exit (1);
-    }
+    win32_event_increment(&qemu_event_handle);
 }
 
 static void qemu_kvm_eat_signals(CPUState *env)
@@ -564,11 +498,10 @@  void qemu_cpu_kick_self(void)
 #endif
 }
 
-void qemu_notify_event(void)
+static void qemu_stop_all_vcpus(void)
 {
     CPUState *env = cpu_single_env;
 
-    qemu_event_increment ();
     if (env) {
         cpu_exit(env);
     }
@@ -578,6 +511,12 @@  void qemu_notify_event(void)
     exit_request = 1;
 }
 
+void qemu_notify_event(void)
+{
+    qemu_event_increment();
+    qemu_stop_all_vcpus();
+}
+
 void qemu_mutex_lock_iothread(void) {}
 void qemu_mutex_unlock_iothread(void) {}
 
diff --git a/qemu-ioh.c b/qemu-ioh.c
index cc71470..5c3f94c 100644
--- a/qemu-ioh.c
+++ b/qemu-ioh.c
@@ -22,7 +22,11 @@ 
  * THE SOFTWARE.
  */
 #include "qemu-ioh.h"
+#include "qemu-char.h"
 #include "qlist.h"
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
 
 /* XXX: fd_read_poll should be suppressed, but an API change is
    necessary in the character devices to suppress fd_can_read(). */
@@ -113,3 +117,94 @@  void qemu_process_fd_handlers2(void *ioh_record_list, const fd_set *rfds,
         }
     }
 }
+
+#ifndef _WIN32
+void iothread_event_increment(int *io_thread_fd)
+{
+    /* Write 8 bytes to be compatible with eventfd.  */
+    static const uint64_t val = 1;
+    ssize_t ret;
+
+    if (*io_thread_fd == -1) {
+        return;
+    }
+
+    do {
+        ret = write(*io_thread_fd, &val, sizeof(val));
+    } while (ret < 0 && errno == EINTR);
+
+    /* EAGAIN is fine, a read must be pending.  */
+    if (ret < 0 && errno != EAGAIN) {
+        fprintf(stderr, "qemu_event_increment: write() filed: %s\n",
+                strerror(errno));
+        exit (1);
+    }
+}
+
+static void qemu_event_read(void *opaque)
+{
+    int fd = (unsigned long)opaque;
+    ssize_t len;
+    char buffer[512];
+
+    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
+    do {
+        len = read(fd, buffer, sizeof(buffer));
+    } while (len == -1 && errno == EINTR);
+}
+
+
+int iothread_event_init(int *io_thread_fd)
+{
+    int err;
+    int fds[2];
+
+    err = qemu_eventfd(fds);
+    if (err == -1)
+        return -errno;
+
+    err = fcntl_setfl(fds[0], O_NONBLOCK);
+    if (err < 0)
+        goto fail;
+
+    err = fcntl_setfl(fds[1], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+
+    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+                         (void *)(unsigned long)fds[0]);
+
+    *io_thread_fd = fds[1];
+    return 0;
+
+fail:
+    close(fds[0]);
+    close(fds[1]);
+    return err;
+}
+#else
+static void dummy_event_handler(void *opaque)
+{
+}
+
+int win32_event_init(HANDLE *qemu_event_handle)
+{
+    *qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!qemu_event_handle) {
+        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+        return -1;
+    }
+    qemu_add_wait_object(*qemu_event_handle, dummy_event_handler, NULL);
+    return 0;
+}
+
+void win32_event_increment(HANDLE *qemu_event_handle)
+{
+    if (!SetEvent(*qemu_event_handle)) {
+        fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
+                GetLastError());
+        exit (1);
+    }
+}
+#endif
diff --git a/qemu-ioh.h b/qemu-ioh.h
index 7c6e833..2c714a9 100644
--- a/qemu-ioh.h
+++ b/qemu-ioh.h
@@ -31,4 +31,13 @@  void qemu_get_fdset2(void *ioh_record_list, int *nfds, fd_set *rfds,
 void qemu_process_fd_handlers2(void *ioh_record_list, const fd_set *rfds,
                                const fd_set *wfds, const fd_set *xfds);
 
+
+#ifndef _WIN32
+void iothread_event_increment(int *io_thread_fd);
+int iothread_event_init(int *io_thread_fd);
+#else
+int win32_event_init(HANDLE *qemu_event_handle);
+void win32_event_increment(HANDLE *qemu_event_handle);
+#endif
+
 #endif
diff --git a/qemu-tool.c b/qemu-tool.c
index 78d3532..027ea31 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -12,6 +12,7 @@ 
  */
 
 #include "qemu-common.h"
+#include "qemu-tool.h"
 #include "monitor.h"
 #include "qemu-timer.h"
 #include "qemu-log.h"
@@ -19,12 +20,11 @@ 
 
 #include <sys/time.h>
 
-QEMUClock *rt_clock;
+QEMUClock *rtc_clock;
 
 FILE *logfile;
 static QLIST_HEAD(, IOHandlerRecord) io_handlers =
     QLIST_HEAD_INITIALIZER(io_handlers);
-
 struct QEMUBH
 {
     QEMUBHFunc *cb;
@@ -134,3 +134,91 @@  void qemu_process_fd_handlers(const fd_set *rfds, const fd_set *wfds,
 {
     return qemu_process_fd_handlers2(&io_handlers, rfds, wfds, xfds);
 }
+
+#ifndef _WIN32
+static int io_thread_fd = -1;
+
+void qemu_event_increment(void)
+{
+    return iothread_event_increment(&io_thread_fd);
+}
+
+int qemu_event_init(void)
+{
+    return iothread_event_init(&io_thread_fd);
+}
+#else
+HANDLE qemu_event_handle;
+
+int qemu_event_init(void)
+{
+    return win32_event_init(&qemu_event_handle);
+}
+
+void qemu_event_increment(void)
+{
+    win32_event_increment(&qemu_event_handle);
+}
+#endif
+
+void qemu_notify_event(void)
+{
+    qemu_event_increment ();
+}
+
+/*
+ * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
+ */
+int qemu_eventfd(int fds[2])
+{
+#ifdef CONFIG_EVENTFD
+    int ret;
+
+    ret = eventfd(0, 0);
+    if (ret >= 0) {
+        fds[0] = ret;
+        qemu_set_cloexec(ret);
+        if ((fds[1] = dup(ret)) == -1) {
+            close(ret);
+            return -1;
+        }
+        qemu_set_cloexec(fds[1]);
+        return 0;
+    }
+
+    if (errno != ENOSYS) {
+        return -1;
+    }
+#endif
+
+    return qemu_pipe(fds);
+}
+
+void qemu_put_be64(QEMUFile *f, uint64_t v)
+{
+}
+
+uint64_t qemu_get_be64(QEMUFile *f)
+{
+    return 0;
+}
+
+const VMStateInfo vmstate_info_int64;
+int use_icount = 0;
+int vm_running = 1;
+int64_t qemu_icount;
+
+int vmstate_register(DeviceState *dev, int instance_id,
+                     const VMStateDescription *vmsd, void *opaque)
+{
+    return 0;
+}
+int64_t cpu_get_icount(void) {
+    return 0;
+}
+
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+                                                     void *opaque)
+{
+    return NULL;
+}
diff --git a/qemu-tool.h b/qemu-tool.h
new file mode 100644
index 0000000..fd693cf
--- /dev/null
+++ b/qemu-tool.h
@@ -0,0 +1,26 @@ 
+#ifndef QEMU_TOOL_H
+#define QEMU_TOOL_H
+
+#include "qemu-common.h"
+
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+typedef void VMStateDescription;
+typedef int VMStateInfo;
+
+#ifndef _WIN32
+void qemu_event_increment(void);
+int qemu_event_init(void);
+#else
+int qemu_event_init(void);
+void qemu_event_increment(void);
+#endif
+
+void qemu_put_be64(QEMUFile *f, uint64_t v);
+uint64_t qemu_get_be64(QEMUFile *f);
+int vmstate_register(DeviceState *dev, int instance_id,
+                     const VMStateDescription *vmsd, void *opaque);
+
+#endif