Signed-off-by: Yonit Halperin <yhalperi@xxxxxxxxxx> --- 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel