[dm-devel] [Bcache v15 07/16] Closures

Kent Overstreet koverstreet at google.com
Mon Jul 23 23:50:50 UTC 2012


Closures are asynchronous refcounty things based on workqueues, used
extensively in bcache.

Signed-off-by: Kent Overstreet <koverstreet at google.com>
---
 include/linux/closure.h |   88 ++++++++++++++++++++++++++---------------------
 lib/closure.c           |   26 +++++++------
 2 files changed, 63 insertions(+), 51 deletions(-)

diff --git a/include/linux/closure.h b/include/linux/closure.h
index 7cae8cf..9537e18 100644
--- a/include/linux/closure.h
+++ b/include/linux/closure.h
@@ -160,7 +160,7 @@
  * enough:
  * struct closure_with_timer;
  *
- * This gives you access to closure_sleep(). It takes a refcount for a specified
+ * This gives you access to closure_delay(). It takes a refcount for a specified
  * number of jiffies - you could then call closure_sync() (for a slightly
  * convoluted version of msleep()) or continue_at() - which gives you the same
  * effect as using a delayed work item, except you can reuse the work_struct
@@ -187,22 +187,6 @@ enum closure_type {
 	MAX_CLOSURE_TYPE			= 3,
 };
 
-enum closure_state_bits {
-	CLOSURE_REMAINING_END	= 20,
-	CLOSURE_BLOCKING_GUARD	= 20,
-	CLOSURE_BLOCKING_BIT	= 21,
-	CLOSURE_WAITING_GUARD	= 22,
-	CLOSURE_WAITING_BIT	= 23,
-	CLOSURE_SLEEPING_GUARD	= 24,
-	CLOSURE_SLEEPING_BIT	= 25,
-	CLOSURE_TIMER_GUARD	= 26,
-	CLOSURE_TIMER_BIT	= 27,
-	CLOSURE_RUNNING_GUARD	= 28,
-	CLOSURE_RUNNING_BIT	= 29,
-	CLOSURE_STACK_GUARD	= 30,
-	CLOSURE_STACK_BIT	= 31,
-};
-
 enum closure_state {
 	/*
 	 * CLOSURE_BLOCKING: Causes closure_wait_event() to block, instead of
@@ -234,23 +218,21 @@ enum closure_state {
 	 * closure with this flag set
 	 */
 
-	CLOSURE_BLOCKING	= (1 << CLOSURE_BLOCKING_BIT),
-	CLOSURE_WAITING		= (1 << CLOSURE_WAITING_BIT),
-	CLOSURE_SLEEPING	= (1 << CLOSURE_SLEEPING_BIT),
-	CLOSURE_TIMER		= (1 << CLOSURE_TIMER_BIT),
-	CLOSURE_RUNNING		= (1 << CLOSURE_RUNNING_BIT),
-	CLOSURE_STACK		= (1 << CLOSURE_STACK_BIT),
+	CLOSURE_BITS_START	= (1 << 19),
+	CLOSURE_DESTRUCTOR	= (1 << 19),
+	CLOSURE_BLOCKING	= (1 << 21),
+	CLOSURE_WAITING		= (1 << 23),
+	CLOSURE_SLEEPING	= (1 << 25),
+	CLOSURE_TIMER		= (1 << 27),
+	CLOSURE_RUNNING		= (1 << 29),
+	CLOSURE_STACK		= (1 << 31),
 };
 
 #define CLOSURE_GUARD_MASK					\
-	((1 << CLOSURE_BLOCKING_GUARD)|				\
-	 (1 << CLOSURE_WAITING_GUARD)|				\
-	 (1 << CLOSURE_SLEEPING_GUARD)|				\
-	 (1 << CLOSURE_TIMER_GUARD)|				\
-	 (1 << CLOSURE_RUNNING_GUARD)|				\
-	 (1 << CLOSURE_STACK_GUARD))
-
-#define CLOSURE_REMAINING_MASK		((1 << CLOSURE_REMAINING_END) - 1)
+	((CLOSURE_DESTRUCTOR|CLOSURE_BLOCKING|CLOSURE_WAITING|	\
+	  CLOSURE_SLEEPING|CLOSURE_TIMER|CLOSURE_RUNNING|CLOSURE_STACK) << 1)
+
+#define CLOSURE_REMAINING_MASK		(CLOSURE_BITS_START - 1)
 #define CLOSURE_REMAINING_INITIALIZER	(1|CLOSURE_RUNNING)
 
 struct closure {
@@ -324,7 +306,7 @@ void __closure_lock(struct closure *cl, struct closure *parent,
 		    struct closure_waitlist *wait_list);
 
 void do_closure_timer_init(struct closure *cl);
-bool __closure_sleep(struct closure *cl, unsigned long delay,
+bool __closure_delay(struct closure *cl, unsigned long delay,
 		     struct timer_list *timer);
 void __closure_flush(struct closure *cl, struct timer_list *timer);
 void __closure_flush_sync(struct closure *cl, struct timer_list *timer);
@@ -478,7 +460,7 @@ do {								\
 	__closure_lock(__to_internal_closure(cl), parent, &(cl)->wait)
 
 /**
- * closure_sleep() - asynchronous sleep
+ * closure_delay() - delay some number of jiffies
  * @cl:		the closure that will sleep
  * @delay:	the delay in jiffies
  *
@@ -486,8 +468,8 @@ do {								\
  * be used to have a function run after a delay with continue_at(), or
  * closure_sync() may be used for a convoluted version of msleep().
  */
-#define closure_sleep(cl, delay)				\
-	__closure_sleep(__to_internal_closure(cl), delay, &(cl)->timer)
+#define closure_delay(cl, delay)			\
+	__closure_delay(__to_internal_closure(cl), delay, &(cl)->timer)
 
 #define closure_flush(cl)				\
 	__closure_flush(__to_internal_closure(cl), &(cl)->timer)
@@ -638,21 +620,49 @@ static inline void closure_wake_up(struct closure_waitlist *list)
 static inline void set_closure_fn(struct closure *cl, closure_fn *fn,
 				  struct workqueue_struct *wq)
 {
+	BUG_ON(object_is_on_stack(cl));
+	closure_set_ip(cl);
 	cl->fn = fn;
 	cl->wq = wq;
 	/* between atomic_dec() in closure_put() */
 	smp_mb__before_atomic_dec();
 }
 
-#define continue_at(_cl, _fn, _wq, ...)					\
+#define continue_at(_cl, _fn, _wq)					\
 do {									\
-	BUG_ON(!(_cl) || object_is_on_stack(_cl));			\
-	closure_set_ip(_cl);						\
 	set_closure_fn(_cl, _fn, _wq);					\
 	closure_sub(_cl, CLOSURE_RUNNING + 1);				\
-	return __VA_ARGS__;						\
+	return;								\
 } while (0)
 
 #define closure_return(_cl)	continue_at((_cl), NULL, NULL)
 
+#define continue_at_nobarrier(_cl, _fn, _wq)				\
+do {									\
+	set_closure_fn(_cl, _fn, _wq);					\
+	closure_queue(cl);						\
+	return;								\
+} while (0)
+
+#define closure_return_with_destructor(_cl, _destructor)		\
+do {									\
+	set_closure_fn(_cl, _destructor, NULL);				\
+	closure_sub(_cl, CLOSURE_RUNNING - CLOSURE_DESTRUCTOR + 1);	\
+	return;								\
+} while (0)
+
+static inline void closure_call(closure_fn fn, struct closure *cl,
+				struct closure *parent)
+{
+	closure_init(cl, parent);
+	fn(cl);
+}
+
+static inline void closure_trylock_call(closure_fn fn, struct closure *cl,
+					struct closure *parent)
+{
+	if (closure_trylock(cl, parent))
+		fn(cl);
+}
+
 #endif /* _LINUX_CLOSURE_H */
diff --git a/lib/closure.c b/lib/closure.c
index f776b6f..38cce18 100644
--- a/lib/closure.c
+++ b/lib/closure.c
@@ -44,20 +44,19 @@ static struct timer_list *closure_timer(struct closure *cl)
 	}
 }
 
-static void closure_put_after_sub(struct closure *cl, int r)
+static inline void closure_put_after_sub(struct closure *cl, int flags)
 {
-	int rem = r & CLOSURE_REMAINING_MASK;
+	int r = flags & CLOSURE_REMAINING_MASK;
 
-	BUG_ON(r & CLOSURE_GUARD_MASK);
-	/* CLOSURE_BLOCK is the only flag that's allowed when r hits 0 */
-	BUG_ON(!rem && (r & ~CLOSURE_BLOCKING));
+	BUG_ON(flags & CLOSURE_GUARD_MASK);
+	BUG_ON(!r && (flags & ~(CLOSURE_DESTRUCTOR|CLOSURE_BLOCKING)));
 
 	/* Must deliver precisely one wakeup */
-	if (rem == 1 && (r & CLOSURE_SLEEPING))
+	if (r == 1 && (flags & CLOSURE_SLEEPING))
 		wake_up_process(cl->task);
 
-	if (!rem) {
-		if (cl->fn) {
+	if (!r) {
+		if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
 			/* CLOSURE_BLOCKING might be set - clear it */
 			atomic_set(&cl->remaining,
 				   CLOSURE_REMAINING_INITIALIZER);
@@ -73,6 +72,9 @@ static void closure_put_after_sub(struct closure *cl, int r)
 			if (wait)
 				closure_wake_up(wait);
 
+			if (cl->fn)
+				cl->fn(cl);
+
 			if (parent)
 				closure_put(parent);
 		}
@@ -205,7 +207,7 @@ void __closure_lock(struct closure *cl, struct closure *parent,
 }
 EXPORT_SYMBOL_GPL(__closure_lock);
 
-static void closure_sleep_timer_fn(unsigned long data)
+static void closure_delay_timer_fn(unsigned long data)
 {
 	struct closure *cl = (struct closure *) data;
 	closure_sub(cl, CLOSURE_TIMER + 1);
@@ -217,11 +219,11 @@ void do_closure_timer_init(struct closure *cl)
 
 	init_timer(timer);
 	timer->data	= (unsigned long) cl;
-	timer->function = closure_sleep_timer_fn;
+	timer->function = closure_delay_timer_fn;
 }
 EXPORT_SYMBOL_GPL(do_closure_timer_init);
 
-bool __closure_sleep(struct closure *cl, unsigned long delay,
+bool __closure_delay(struct closure *cl, unsigned long delay,
 		     struct timer_list *timer)
 {
 	if (atomic_read(&cl->remaining) & CLOSURE_TIMER)
@@ -235,7 +237,7 @@ bool __closure_sleep(struct closure *cl, unsigned long delay,
 	add_timer(timer);
 	return true;
 }
-EXPORT_SYMBOL_GPL(__closure_sleep);
+EXPORT_SYMBOL_GPL(__closure_delay);
 
 void __closure_flush(struct closure *cl, struct timer_list *timer)
 {
-- 
1.7.7.3




More information about the dm-devel mailing list