From: Huang Ying <ying.huang@intel.com> To: Andrew Morton <akpm@linux-foundation.org> Cc: linux-kernel@vger.kernel.org, Andi Kleen <andi@firstfloor.org>, ying.huang@intel.com, Peter Zijlstra <peterz@infradead.org>, Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Subject: [PATCH -mm -v2 5/5] irq_work, Use llist in irq_work Date: Thu, 8 Sep 2011 14:00:46 +0800 [thread overview] Message-ID: <1315461646-1379-6-git-send-email-ying.huang@intel.com> (raw) In-Reply-To: <1315461646-1379-1-git-send-email-ying.huang@intel.com> Use llist in irq_work instead of the lock-less linked list implementation in irq_work to avoid the code duplication. Signed-off-by: Huang Ying <ying.huang@intel.com> Cc: Peter Zijlstra <peterz@infradead.org> --- include/linux/irq_work.h | 15 ++++--- kernel/irq_work.c | 92 ++++++++++++++++------------------------------- 2 files changed, 42 insertions(+), 65 deletions(-) --- a/include/linux/irq_work.h +++ b/include/linux/irq_work.h @@ -1,20 +1,23 @@ #ifndef _LINUX_IRQ_WORK_H #define _LINUX_IRQ_WORK_H +#include <linux/llist.h> + struct irq_work { - struct irq_work *next; + unsigned long flags; + struct llist_node llnode; void (*func)(struct irq_work *); }; static inline -void init_irq_work(struct irq_work *entry, void (*func)(struct irq_work *)) +void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *)) { - entry->next = NULL; - entry->func = func; + work->flags = 0; + work->func = func; } -bool irq_work_queue(struct irq_work *entry); +bool irq_work_queue(struct irq_work *work); void irq_work_run(void); -void irq_work_sync(struct irq_work *entry); +void irq_work_sync(struct irq_work *work); #endif /* _LINUX_IRQ_WORK_H */ --- a/kernel/irq_work.c +++ b/kernel/irq_work.c @@ -10,7 +10,6 @@ #include <linux/irq_work.h> #include <linux/percpu.h> #include <linux/hardirq.h> -#include <asm/processor.h> /* * An entry can be in one of four states: @@ -19,54 +18,34 @@ * claimed NULL, 3 -> {pending} : claimed to be enqueued * pending next, 3 -> {busy} : queued, pending callback * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed - * - * We use the lower two bits of the next pointer to keep PENDING and BUSY - * flags. */ #define IRQ_WORK_PENDING 1UL #define IRQ_WORK_BUSY 2UL #define IRQ_WORK_FLAGS 3UL -static inline bool irq_work_is_set(struct irq_work *entry, int flags) -{ - return (unsigned long)entry->next & flags; -} - -static inline struct irq_work *irq_work_next(struct irq_work *entry) -{ - unsigned long next = (unsigned long)entry->next; - next &= ~IRQ_WORK_FLAGS; - return (struct irq_work *)next; -} - -static inline struct irq_work *next_flags(struct irq_work *entry, int flags) -{ - unsigned long next = (unsigned long)entry; - next |= flags; - return (struct irq_work *)next; -} - -static DEFINE_PER_CPU(struct irq_work *, irq_work_list); +static DEFINE_PER_CPU(struct llist_head, irq_work_list); /* * Claim the entry so that no one else will poke at it. */ -static bool irq_work_claim(struct irq_work *entry) +static bool irq_work_claim(struct irq_work *work) { - struct irq_work *next, *nflags; + unsigned long flags, nflags; - do { - next = entry->next; - if ((unsigned long)next & IRQ_WORK_PENDING) + for (;;) { + flags = work->flags; + if (flags & IRQ_WORK_PENDING) return false; - nflags = next_flags(next, IRQ_WORK_FLAGS); - } while (cmpxchg(&entry->next, next, nflags) != next); + nflags = flags | IRQ_WORK_FLAGS; + if (cmpxchg(&work->flags, flags, nflags) == flags) + break; + cpu_relax(); + } return true; } - void __weak arch_irq_work_raise(void) { /* @@ -77,20 +56,15 @@ void __weak arch_irq_work_raise(void) /* * Queue the entry and raise the IPI if needed. */ -static void __irq_work_queue(struct irq_work *entry) +static void __irq_work_queue(struct irq_work *work) { - struct irq_work *next; + bool empty; preempt_disable(); - do { - next = __this_cpu_read(irq_work_list); - /* Can assign non-atomic because we keep the flags set. */ - entry->next = next_flags(next, IRQ_WORK_FLAGS); - } while (this_cpu_cmpxchg(irq_work_list, next, entry) != next); - + empty = llist_add(&work->llnode, &__get_cpu_var(irq_work_list)); /* The list was empty, raise self-interrupt to start processing. */ - if (!irq_work_next(entry)) + if (empty) arch_irq_work_raise(); preempt_enable(); @@ -102,16 +76,16 @@ static void __irq_work_queue(struct irq_ * * Can be re-enqueued while the callback is still in progress. */ -bool irq_work_queue(struct irq_work *entry) +bool irq_work_queue(struct irq_work *work) { - if (!irq_work_claim(entry)) { + if (!irq_work_claim(work)) { /* * Already enqueued, can't do! */ return false; } - __irq_work_queue(entry); + __irq_work_queue(work); return true; } EXPORT_SYMBOL_GPL(irq_work_queue); @@ -122,34 +96,34 @@ EXPORT_SYMBOL_GPL(irq_work_queue); */ void irq_work_run(void) { - struct irq_work *list; + struct irq_work *work; + struct llist_head *this_list; + struct llist_node *llnode; - if (this_cpu_read(irq_work_list) == NULL) + this_list = &__get_cpu_var(irq_work_list); + if (llist_empty(this_list)) return; BUG_ON(!in_irq()); BUG_ON(!irqs_disabled()); - list = this_cpu_xchg(irq_work_list, NULL); - - while (list != NULL) { - struct irq_work *entry = list; + llnode = llist_del_all(this_list); + while (llnode != NULL) { + work = llist_entry(llnode, struct irq_work, llnode); - list = irq_work_next(list); + llnode = llnode->next; /* - * Clear the PENDING bit, after this point the @entry + * Clear the PENDING bit, after this point the @work * can be re-used. */ - entry->next = next_flags(NULL, IRQ_WORK_BUSY); - entry->func(entry); + work->flags = IRQ_WORK_BUSY; + work->func(work); /* * Clear the BUSY bit and return to the free state if * no-one else claimed it meanwhile. */ - (void)cmpxchg(&entry->next, - next_flags(NULL, IRQ_WORK_BUSY), - NULL); + (void)cmpxchg(&work->flags, IRQ_WORK_BUSY, 0); } } EXPORT_SYMBOL_GPL(irq_work_run); @@ -158,11 +132,11 @@ EXPORT_SYMBOL_GPL(irq_work_run); * Synchronize against the irq_work @entry, ensures the entry is not * currently in use. */ -void irq_work_sync(struct irq_work *entry) +void irq_work_sync(struct irq_work *work) { WARN_ON_ONCE(irqs_disabled()); - while (irq_work_is_set(entry, IRQ_WORK_BUSY)) + while (work->flags & IRQ_WORK_BUSY) cpu_relax(); } EXPORT_SYMBOL_GPL(irq_work_sync);
next prev parent reply other threads:[~2011-09-08 6:01 UTC|newest] Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top 2011-09-08 6:00 [PATCH -mm -v2 0/5] " Huang Ying 2011-09-08 6:00 ` [PATCH -mm -v2 1/5] llist, Make all llist functions inline Huang Ying 2011-09-08 6:00 ` [PATCH -mm -v2 2/5] llist, Define macro to check NMI safe cmpxchg Huang Ying 2011-09-08 6:00 ` [PATCH -mm -v2 3/5] llist, Move cpu_relax after cmpxchg Huang Ying 2011-09-08 6:00 ` [PATCH -mm -v2 4/5] llist, Return whether list is empty before adding in llist_add Huang Ying 2011-09-08 6:00 ` Huang Ying [this message] 2011-09-12 14:05 ` [PATCH 6/5] llist: Add llist_next() Peter Zijlstra 2011-09-12 14:05 ` [PATCH 7/5] sched: Convert to use llist Peter Zijlstra 2011-09-12 14:05 ` [PATCH 8/5] llist: Remove cpu_relax() usage in cmpxchg loops Peter Zijlstra 2011-09-12 14:23 ` Andi Kleen 2011-09-12 14:23 ` Peter Zijlstra 2011-09-12 14:47 ` Mathieu Desnoyers 2011-09-12 15:09 ` Peter Zijlstra 2011-09-12 15:24 ` Peter Zijlstra 2011-09-12 16:38 ` Andi Kleen 2011-09-12 18:53 ` Peter Zijlstra 2011-09-12 14:26 ` Avi Kivity 2011-09-12 14:32 ` Peter Zijlstra 2011-09-13 11:43 ` Avi Kivity 2011-09-13 14:22 ` Peter Zijlstra 2011-09-13 14:51 ` Avi Kivity 2011-09-13 14:53 ` Peter Zijlstra 2011-09-12 14:06 ` [PATCH -mm -v2 0/5] irq_work, Use llist in irq_work Peter Zijlstra
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1315461646-1379-6-git-send-email-ying.huang@intel.com \ --to=ying.huang@intel.com \ --cc=akpm@linux-foundation.org \ --cc=andi@firstfloor.org \ --cc=linux-kernel@vger.kernel.org \ --cc=mathieu.desnoyers@efficios.com \ --cc=peterz@infradead.org \ --subject='Re: [PATCH -mm -v2 5/5] irq_work, Use llist in irq_work' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.