aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/notifier.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-05-18 13:23:02 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-05-18 13:23:02 +0100
commitafb3100a1d8da9516fc946d9d061ba7441d1cf51 (patch)
tree9ccc45dbe03963dc19296c626ce7afb62f8470c8 /xen/common/notifier.c
parent6cbd479e30dc414af9b892e96412920a753391cd (diff)
downloadxen-afb3100a1d8da9516fc946d9d061ba7441d1cf51.tar.gz
xen-afb3100a1d8da9516fc946d9d061ba7441d1cf51.tar.bz2
xen-afb3100a1d8da9516fc946d9d061ba7441d1cf51.zip
Clean up notifier-chain interface and use new interface in CPU hotplug.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/common/notifier.c')
-rw-r--r--xen/common/notifier.c166
1 files changed, 51 insertions, 115 deletions
diff --git a/xen/common/notifier.c b/xen/common/notifier.c
index fe1c507a7a..ea1ebdeffe 100644
--- a/xen/common/notifier.c
+++ b/xen/common/notifier.c
@@ -10,147 +10,83 @@
#include <xen/config.h>
#include <xen/init.h>
#include <xen/notifier.h>
-#include <xen/rcupdate.h>
-
-/*
- * Notifier chain core routines. The exported routines below
- * are layered on top of these, with appropriate locking added.
- */
-
-static int notifier_chain_register(
- struct notifier_block **nl, struct notifier_block *n)
-{
- while ( (*nl) != NULL )
- {
- if ( n->priority > (*nl)->priority )
- break;
- nl = &((*nl)->next);
- }
- n->next = *nl;
- rcu_assign_pointer(*nl, n);
- return 0;
-}
-
-static int notifier_chain_unregister(
- struct notifier_block **nl, struct notifier_block *n)
-{
- while ( (*nl) != NULL )
- {
- if ( (*nl) == n )
- {
- rcu_assign_pointer(*nl, n->next);
- return 0;
- }
- nl = &((*nl)->next);
- }
- return -ENOENT;
-}
-
-/**
- * notifier_call_chain - Informs the registered notifiers about an event.
- * @nl: Pointer to head of the blocking notifier chain
- * @val: Value passed unmodified to notifier function
- * @v: Pointer passed unmodified to notifier function
- * @nr_to_call: Number of notifier functions to be called. Don't care
- * value of this parameter is -1.
- * @nr_calls: Records the number of notifications sent. Don't care
- * value of this field is NULL.
- * @returns: notifier_call_chain returns the value returned by the
- * last notifier function called.
- */
-static int notifier_call_chain(
- struct notifier_block **nl, unsigned long val, void *v,
- int nr_to_call, int *nr_calls)
-{
- int ret = NOTIFY_DONE;
- struct notifier_block *nb, *next_nb;
-
- if ( nr_calls )
- *nr_calls = 0;
-
- nb = rcu_dereference(*nl);
-
- while ( nb && nr_to_call )
- {
- next_nb = rcu_dereference(nb->next);
- ret = nb->notifier_call(nb, val, v);
-
- if ( nr_calls )
- (*nr_calls)++;
-
- if ( (ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK )
- break;
- nb = next_nb;
- nr_to_call--;
- }
- return ret;
-}
-
-/*
- * Raw notifier chain routines. There is no protection;
- * the caller must provide it. Use at your own risk!
- */
/**
- * raw_notifier_chain_register - Add notifier to a raw notifier chain
+ * notifier_chain_register - Add notifier to a raw notifier chain
* @nh: Pointer to head of the raw notifier chain
* @n: New entry in notifier chain
*
* Adds a notifier to a raw notifier chain.
* All locking must be provided by the caller.
- *
- * Currently always returns zero.
*/
-int raw_notifier_chain_register(
- struct raw_notifier_head *nh, struct notifier_block *n)
+void notifier_chain_register(
+ struct notifier_head *nh, struct notifier_block *n)
{
- return notifier_chain_register(&nh->head, n);
+ struct list_head *chain = &nh->head.chain;
+ struct notifier_block *nb;
+
+ while ( chain->next != &nh->head.chain )
+ {
+ nb = list_entry(chain->next, struct notifier_block, chain);
+ if ( n->priority > nb->priority )
+ break;
+ chain = chain->next;
+ }
+
+ list_add(&n->chain, chain);
}
/**
- * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain
+ * notifier_chain_unregister - Remove notifier from a raw notifier chain
* @nh: Pointer to head of the raw notifier chain
* @n: Entry to remove from notifier chain
*
* Removes a notifier from a raw notifier chain.
* All locking must be provided by the caller.
- *
- * Returns zero on success or %-ENOENT on failure.
*/
-int raw_notifier_chain_unregister(
- struct raw_notifier_head *nh, struct notifier_block *n)
+void notifier_chain_unregister(
+ struct notifier_head *nh, struct notifier_block *n)
{
- return notifier_chain_unregister(&nh->head, n);
+ list_del(&n->chain);
}
/**
- * __raw_notifier_call_chain - Call functions in a raw notifier chain
+ * notifier_call_chain - Informs the registered notifiers about an event.
* @nh: Pointer to head of the raw notifier chain
- * @val: Value passed unmodified to notifier function
- * @v: Pointer passed unmodified to notifier function
- * @nr_to_call: See comment for notifier_call_chain.
- * @nr_calls: See comment for notifier_call_chain
+ * @val: Value passed unmodified to notifier function
+ * @v: Pointer passed unmodified to notifier function
+ * @pcursor: If non-NULL, position in chain to start from. Also updated on
+ * return to indicate how far notifications got before stopping.
*
- * Calls each function in a notifier chain in turn. The functions
- * run in an undefined context.
- * All locking must be provided by the caller.
+ * Calls each function in a notifier chain in turn. The functions run in an
+ * undefined context. All locking must be provided by the caller.
*
- * If the return value of the notifier can be and'ed
- * with %NOTIFY_STOP_MASK then raw_notifier_call_chain()
- * will return immediately, with the return value of
- * the notifier function which halted execution.
- * Otherwise the return value is the return value
- * of the last notifier function called.
+ * If the return value of the notifier can be and'ed with %NOTIFY_STOP_MASK
+ * then notifier_call_chain() will return immediately, with teh return value of
+ * the notifier function which halted execution. Otherwise the return value is
+ * the return value of the last notifier function called.
*/
-int __raw_notifier_call_chain(
- struct raw_notifier_head *nh, unsigned long val, void *v,
- int nr_to_call, int *nr_calls)
+int notifier_call_chain(
+ struct notifier_head *nh, unsigned long val, void *v,
+ struct notifier_block **pcursor)
{
- return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
-}
+ int ret = NOTIFY_DONE;
+ struct list_head *cursor;
+ struct notifier_block *nb;
+ bool_t reverse = !!(val & NOTIFY_REVERSE);
-int raw_notifier_call_chain(
- struct raw_notifier_head *nh, unsigned long val, void *v)
-{
- return __raw_notifier_call_chain(nh, val, v, -1, NULL);
+ cursor = &(pcursor && *pcursor ? *pcursor : &nh->head)->chain;
+
+ do {
+ cursor = reverse ? cursor->prev : cursor->next;
+ nb = list_entry(cursor, struct notifier_block, chain);
+ if ( cursor == &nh->head.chain )
+ break;
+ ret = nb->notifier_call(nb, val, v);
+ } while ( !(ret & NOTIFY_STOP_MASK) );
+
+ if ( pcursor )
+ *pcursor = nb;
+
+ return ret;
}