[Spice-devel] [RFC PATCH 1/4] notifiers: add support for async notifiers handlers
Yonit Halperin
yhalperi at redhat.com
Wed May 30 02:02:36 PDT 2012
Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
---
input.c | 2 +-
migration.c | 2 +-
notify.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
notify.h | 55 ++++++++++++++++++++++++++++++++++++---
qemu-timer.c | 2 +-
vl.c | 2 +-
6 files changed, 129 insertions(+), 13 deletions(-)
diff --git a/input.c b/input.c
index 6968b31..06f6f9f 100644
--- a/input.c
+++ b/input.c
@@ -274,5 +274,5 @@ void qemu_add_mouse_mode_change_notifier(Notifier *notify)
void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
{
- notifier_remove(notify);
+ notifier_remove(¬ify->base);
}
diff --git a/migration.c b/migration.c
index 3f485d3..acaf293 100644
--- a/migration.c
+++ b/migration.c
@@ -320,7 +320,7 @@ void add_migration_state_change_notifier(Notifier *notify)
void remove_migration_state_change_notifier(Notifier *notify)
{
- notifier_remove(notify);
+ notifier_remove(¬ify->base);
}
bool migration_is_active(MigrationState *s)
diff --git a/notify.c b/notify.c
index 12282a6..dde190e 100644
--- a/notify.c
+++ b/notify.c
@@ -19,23 +19,94 @@
void notifier_list_init(NotifierList *list)
{
QLIST_INIT(&list->notifiers);
+ QLIST_INIT(&list->wait_notifiers);
}
void notifier_list_add(NotifierList *list, Notifier *notifier)
{
- QLIST_INSERT_HEAD(&list->notifiers, notifier, node);
+ notifier->base.type = NOTIFIER_TYPE_SYNC;
+ QLIST_INSERT_HEAD(&list->notifiers, ¬ifier->base, node);
}
-void notifier_remove(Notifier *notifier)
+void notifier_list_add_async(NotifierList *list, AsyncNotifier *notifier)
+{
+ notifier->base.type = NOTIFIER_TYPE_ASYNC;
+ QLIST_INSERT_HEAD(&list->notifiers, ¬ifier->base, node);
+}
+
+void notifier_remove(BaseNotifier *notifier)
{
QLIST_REMOVE(notifier, node);
}
+static void notified_complete_cb(AsyncNotifier *notifier, void *opaque)
+{
+ NotifierList *list = opaque;
+
+ QLIST_REMOVE(notifier, wait_node);
+
+ if (QLIST_EMPTY(&list->wait_notifiers) && !list->during_notify) {
+ if (list->complete_cb) {
+ list->complete_cb(list->complete_opaque);
+ }
+ }
+}
+
void notifier_list_notify(NotifierList *list, void *data)
{
- Notifier *notifier, *next;
+ BaseNotifier *notifier, *next;
+ bool async = false;
+
+ if (notifier_list_async_waiting(list)) {
+ AsyncNotifier *wait_notifier, *wait_next;
+
+ fprintf(stderr, "%s: previous notify hasn't completed\n", __func__);
+ QLIST_FOREACH_SAFE(wait_notifier, &list->wait_notifiers,
+ wait_node, wait_next) {
+ QLIST_REMOVE(wait_notifier, wait_node);
+ }
+
+ }
+
+ list->during_notify = true;
QLIST_FOREACH_SAFE(notifier, &list->notifiers, node, next) {
- notifier->notify(notifier, data);
+ switch (notifier->type) {
+ case NOTIFIER_TYPE_SYNC:
+ {
+ Notifier *sync_notifier;
+
+ sync_notifier = container_of(notifier, Notifier, base);
+ sync_notifier->notify(sync_notifier, data);
+ break;
+ }
+ case NOTIFIER_TYPE_ASYNC:
+ {
+ AsyncNotifier *async_notifier;
+
+ async = true;
+ async_notifier = container_of(notifier, AsyncNotifier, base);
+ QLIST_INSERT_HEAD(&list->wait_notifiers,
+ async_notifier,
+ wait_node);
+ async_notifier->notify_async(async_notifier, data,
+ notified_complete_cb, list);
+ break;
+ }
+ default:
+ fprintf(stderr, "%s: invalid notifier type %d\n", __func__,
+ notifier->type);
+ break;
+ }
}
+
+ list->during_notify = false;
+ if ((!async || !notifier_list_async_waiting(list)) && list->complete_cb) {
+ list->complete_cb(list->complete_opaque);
+ }
+}
+
+bool notifier_list_async_waiting(NotifierList *list)
+{
+ return !QLIST_EMPTY(&list->wait_notifiers);
}
diff --git a/notify.h b/notify.h
index 03cf26c..8660920 100644
--- a/notify.h
+++ b/notify.h
@@ -16,28 +16,73 @@
#include "qemu-queue.h"
+typedef enum NotifierType {
+ NOTIFIER_TYPE_NONE,
+ NOTIFIER_TYPE_SYNC,
+ NOTIFIER_TYPE_ASYNC,
+} NotifierType;
+
+typedef struct BaseNotifier BaseNotifier;
+
+struct BaseNotifier {
+ QLIST_ENTRY(BaseNotifier) node;
+ NotifierType type;
+};
typedef struct Notifier Notifier;
struct Notifier
{
+ BaseNotifier base;
void (*notify)(Notifier *notifier, void *data);
- QLIST_ENTRY(Notifier) node;
};
+typedef struct AsyncNotifier AsyncNotifier;
+typedef void (NotifiedCompletionFunc)(AsyncNotifier *notifier, void *opaque);
+
+struct AsyncNotifier {
+ BaseNotifier base;
+ void (*notify_async)(AsyncNotifier *notifier, void *data,
+ NotifiedCompletionFunc *complete_cb, void *cb_data);
+ QLIST_ENTRY(AsyncNotifier) wait_node;
+};
+
+typedef void (NotifyListCompletion)(void *opaque);
+
typedef struct NotifierList
{
- QLIST_HEAD(, Notifier) notifiers;
+ QLIST_HEAD(, BaseNotifier) notifiers;
+
+ NotifyListCompletion *complete_cb;
+ void *complete_opaque;
+
+ QLIST_HEAD(, AsyncNotifier) wait_notifiers;
+ bool during_notify;
} NotifierList;
-#define NOTIFIER_LIST_INITIALIZER(head) \
- { QLIST_HEAD_INITIALIZER((head).notifiers) }
+#define NOTIFIER_LIST_INITIALIZER(head) \
+ { QLIST_HEAD_INITIALIZER((head).notifiers), \
+ NULL, \
+ NULL, \
+ QLIST_HEAD_INITIALIZER((head).wait_notifiers) \
+ }
+#define ASYNC_NOTIFIER_LIST_INITIALIZER(head, cb, cb_data) \
+ { QLIST_HEAD_INITIALIZER((head).notifiers), \
+ cb, \
+ cb_data, \
+ QLIST_HEAD_INITIALIZER((head).wait_notifiers) \
+ }
void notifier_list_init(NotifierList *list);
void notifier_list_add(NotifierList *list, Notifier *notifier);
+void notifier_list_add_async(NotifierList *list, AsyncNotifier *notifier);
-void notifier_remove(Notifier *notifier);
+void notifier_remove(BaseNotifier *notifier);
void notifier_list_notify(NotifierList *list, void *data);
+/* returns true when there are async notifiers that still hasn't
+ * called complete_cb for the last notification */
+bool notifier_list_async_waiting(NotifierList *list);
+
#endif
diff --git a/qemu-timer.c b/qemu-timer.c
index de98977..2b2f84a 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -430,7 +430,7 @@ void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
{
- notifier_remove(notifier);
+ notifier_remove(¬ifier->base);
}
void init_clocks(void)
diff --git a/vl.c b/vl.c
index 23ab3a3..646b16b 100644
--- a/vl.c
+++ b/vl.c
@@ -2183,7 +2183,7 @@ void qemu_add_exit_notifier(Notifier *notify)
void qemu_remove_exit_notifier(Notifier *notify)
{
- notifier_remove(notify);
+ notifier_remove(¬ify->base);
}
static void qemu_run_exit_notifiers(void)
--
1.7.7.6
More information about the Spice-devel
mailing list