The wait command will pause the monitor the command was issued in until a new event becomes available. Events are queued if there isn't a waiter present. The wait command completes after a single event is available.
Today, we queue events indefinitely but in the future, I suspect we'll drop events that are older than a certain amount of time to avoid infinitely allocating memory for long running VMs. To make use of the new notification mechanism, this patch introduces a qemu_notify_event() API. This API takes three parameters: a class which is meant to classify the type of event being generated, a name which is meant to distinguish which event in the class that has been generated, and a details parameters which is meant to allow events to send arbitrary data with a given event. v1->v2 - Added a -d flag to poll for events instead of waiting - Made old events expire after 10 minutes Signed-off-by: Anthony Liguori <aligu...@us.ibm.com> diff --git a/Makefile b/Makefile index 633774e..b87870b 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OBJS+=usb-serial.o usb-net.o OBJS+=sd.o ssi-sd.o OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o -OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o +OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o wait.o ifdef CONFIG_BRLAPI OBJS+= baum.o diff --git a/monitor.c b/monitor.c index ca1c11c..94c14b2 100644 --- a/monitor.c +++ b/monitor.c @@ -42,6 +42,7 @@ #include "migration.h" #include "kvm.h" #include "acl.h" +#include "wait.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -1745,6 +1746,8 @@ static const mon_cmd_t mon_cmds[] = { "acl allow vnc.username fred\n" "acl deny vnc.username bob\n" "acl reset vnc.username\n" }, + { "wait", "-d", do_wait, + "[-d]", "wait for an asynchronous event (use -d to poll event)" }, { NULL, NULL, }, }; diff --git a/wait.c b/wait.c new file mode 100644 index 0000000..8f6cbad --- /dev/null +++ b/wait.c @@ -0,0 +1,145 @@ +/* + * Asynchronous monitor notification support + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aligu...@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "monitor.h" +#include "sys-queue.h" +#include "osdep.h" +#include "wait.h" + +typedef struct WaitEvent +{ + qemu_timeval timestamp; + char *class; + char *name; + char *details; + TAILQ_ENTRY(WaitEvent) node; +} WaitEvent; + +typedef struct PendingWaiter +{ + Monitor *mon; + int polling; + TAILQ_ENTRY(PendingWaiter) node; +} PendingWaiter; + +/* How long do we hold on to events (in seconds) + * default to 10 minutes. */ +#define EVENT_EXPIRATION_AGE (10 * 60) + +static TAILQ_HEAD(, WaitEvent) pending_events = + TAILQ_HEAD_INITIALIZER(pending_events); +static TAILQ_HEAD(, PendingWaiter) pending_waiters = + TAILQ_HEAD_INITIALIZER(pending_waiters); + +static void free_event(WaitEvent *e) +{ + qemu_free(e->details); + qemu_free(e->name); + qemu_free(e->class); + qemu_free(e); +} + +static void dispatch_event(PendingWaiter *w, WaitEvent *e) +{ + monitor_printf(w->mon, "%ld.%06ld: %s: %s\n", + e->timestamp.tv_sec, e->timestamp.tv_usec, + e->class, e->name); + if (e->details && strlen(e->details)) { + monitor_printf(w->mon, "%s\n", e->details); + } + if (!w->polling) + monitor_resume(w->mon); +} + +static void remove_stale_events(void) +{ + qemu_timeval now; + + qemu_gettimeofday(&now); + + while (!TAILQ_EMPTY(&pending_events)) { + WaitEvent *e; + + e = TAILQ_FIRST(&pending_events); + if ((now.tv_sec - e->timestamp.tv_sec) > EVENT_EXPIRATION_AGE) { + TAILQ_REMOVE(&pending_events, e, node); + free_event(e); + } else { + break; + } + } +} + +static int try_to_process_events(void) +{ + int processed_events = 0; + + while (!TAILQ_EMPTY(&pending_events) && !TAILQ_EMPTY(&pending_waiters)) { + WaitEvent *e; + PendingWaiter *w; + + e = TAILQ_FIRST(&pending_events); + TAILQ_REMOVE(&pending_events, e, node); + + w = TAILQ_FIRST(&pending_waiters); + TAILQ_REMOVE(&pending_waiters, w, node); + + dispatch_event(w, e); + + free_event(e); + qemu_free(w); + + processed_events = 1; + } + + remove_stale_events(); + + return processed_events; +} + +void qemu_notify_event(const char *class, const char *name, const char *details) +{ + WaitEvent *e; + + e = qemu_mallocz(sizeof(*e)); + + qemu_gettimeofday(&e->timestamp); + e->class = qemu_strdup(class); + e->name = qemu_strdup(name); + if (details) + e->details = qemu_strdup(details); + + TAILQ_INSERT_TAIL(&pending_events, e, node); + + try_to_process_events(); +} + +void do_wait(Monitor *mon, int polling) +{ + PendingWaiter *w; + + w = qemu_mallocz(sizeof(*w)); + w->mon = mon; + w->polling = polling; + + TAILQ_INSERT_TAIL(&pending_waiters, w, node); + + if (!w->polling) + monitor_suspend(w->mon); + + if (!try_to_process_events() && w->polling) { + TAILQ_REMOVE(&pending_waiters, w, node); + qemu_free(w); + } +} diff --git a/wait.h b/wait.h new file mode 100644 index 0000000..3fb455f --- /dev/null +++ b/wait.h @@ -0,0 +1,23 @@ +/* + * Asynchronous monitor notification support + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aligu...@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_WAIT_H +#define QEMU_WAIT_H + +#include "monitor.h" + +void qemu_notify_event(const char *class, const char *name, + const char *details); +void do_wait(Monitor *mon, int polling); + +#endif -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list