Patchwork [RFC,1/4] notifiers: add support for async notifiers handlers

login
register
mail settings
Submitter Yonit Halperin
Date May 30, 2012, 9:02 a.m.
Message ID <1338368559-16535-2-git-send-email-yhalperi@redhat.com>
Download mbox | patch
Permalink /patch/161898/
State New
Headers show

Comments

Yonit Halperin - May 30, 2012, 9:02 a.m.
Signed-off-by: Yonit Halperin <yhalperi@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(-)
Alon Levy - May 30, 2012, 9:27 a.m.
On Wed, May 30, 2012 at 12:02:36PM +0300, Yonit Halperin wrote:
> Signed-off-by: Yonit Halperin <yhalperi@redhat.com>

One empty line that snuck in below.

> ---
>  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(&notify->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(&notify->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, &notifier->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, &notifier->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);
> +        }
> +
Unnecessary empty line.

> +    }
> +
> +    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(&notifier->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(&notify->base);
>  }
>  
>  static void qemu_run_exit_notifiers(void)
> -- 
> 1.7.7.6
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel

Patch

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(&notify->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(&notify->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, &notifier->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, &notifier->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(&notifier->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(&notify->base);
 }
 
 static void qemu_run_exit_notifiers(void)