diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2010-05-18 13:23:02 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2010-05-18 13:23:02 +0100 |
commit | afb3100a1d8da9516fc946d9d061ba7441d1cf51 (patch) | |
tree | 9ccc45dbe03963dc19296c626ce7afb62f8470c8 /xen/common/notifier.c | |
parent | 6cbd479e30dc414af9b892e96412920a753391cd (diff) | |
download | xen-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.c | 166 |
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; } |