[PATCH 6/8] PM: Add suspend blocking work.

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Friday, April 30, 2010 - 3:36 pm

Allow work to be queued that will block suspend while it is pending
or executing. To get the same functionality in the calling code often
requires a separate suspend_blocker for pending and executing work, or
additional state and locking. This implementation does add additional
state and locking, but this can be removed later if we add support for
suspend blocking work to the core workqueue code.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_blocker.h |   67 ++++++++++++++++++++++++
 kernel/power/suspend_blocker.c  |  109 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 176 insertions(+), 0 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index c80764c..bf41a57 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -18,6 +18,7 @@
 
 #include <linux/list.h>
 #include <linux/ktime.h>
+#include <linux/workqueue.h>
 
 /**
  * struct suspend_blocker - the basic suspend_blocker structure
@@ -57,6 +58,38 @@ struct suspend_blocker {
 #endif
 };
 
+/**
+ * struct suspend_blocking_work - the basic suspend_blocking_work structure
+ * @work:		Standard work struct.
+ * @suspend_blocker:	Suspend blocker.
+ * @func:		Callback.
+ * @lock:		Spinlock protecting pending and running state.
+ * @active:		Number of cpu workqueues where work is pending or
+ *			callback is running.
+ *
+ * When suspend blocking work is pending or its callback is running it prevents
+ * the system from entering opportunistic suspend.
+ *
+ * The suspend_blocking_work structure must be initialized by
+ * suspend_blocking_work_init().
+ */
+
+struct suspend_blocking_work {
+	struct work_struct work;
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+	struct suspend_blocker suspend_blocker;
+	work_func_t func;
+	spinlock_t lock;
+	int active;
+#endif
+};
+
+static inline struct suspend_blocking_work *to_suspend_blocking_work(
+	struct work_struct *work)
+{
+	return container_of(work, struct suspend_blocking_work, work);
+}
+
 #ifdef CONFIG_OPPORTUNISTIC_SUSPEND
 
 void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
@@ -66,6 +99,14 @@ void suspend_unblock(struct suspend_blocker *blocker);
 bool suspend_blocker_is_active(struct suspend_blocker *blocker);
 bool suspend_is_blocked(void);
 
+void suspend_blocking_work_init(struct suspend_blocking_work *work,
+				work_func_t func, const char *name);
+void suspend_blocking_work_destroy(struct suspend_blocking_work *work);
+int queue_suspend_blocking_work(struct workqueue_struct *wq,
+				struct suspend_blocking_work *work);
+int schedule_suspend_blocking_work(struct suspend_blocking_work *work);
+int cancel_suspend_blocking_work_sync(struct suspend_blocking_work *work);
+
 #else
 
 static inline void suspend_blocker_init(struct suspend_blocker *blocker,
@@ -77,6 +118,32 @@ static inline bool suspend_blocker_is_active(struct suspend_blocker *bl)
 								{ return 0; }
 static inline bool suspend_is_blocked(void) { return 0; }
 
+static inline void suspend_blocking_work_init(
+	struct suspend_blocking_work *work, work_func_t func, const char *name)
+{
+	INIT_WORK(&work->work, func);
+}
+static inline void suspend_blocking_work_destroy(
+	struct suspend_blocking_work *work)
+{
+	cancel_work_sync(&work->work);
+}
+static inline int queue_suspend_blocking_work(
+	struct workqueue_struct *wq, struct suspend_blocking_work *work)
+{
+	return queue_work(wq, &work->work);
+}
+static inline int schedule_suspend_blocking_work(
+	struct suspend_blocking_work *work)
+{
+	return schedule_work(&work->work);
+}
+static inline int cancel_suspend_blocking_work_sync(
+	struct suspend_blocking_work *work)
+{
+	return cancel_work_sync(&work->work);
+}
+
 #endif
 
 #endif
diff --git a/kernel/power/suspend_blocker.c b/kernel/power/suspend_blocker.c
index 77920e6..852d941 100644
--- a/kernel/power/suspend_blocker.c
+++ b/kernel/power/suspend_blocker.c
@@ -474,3 +474,112 @@ static int __init suspend_block_postcore_init(void)
 }
 
 postcore_initcall(suspend_block_postcore_init);
+
+static void suspend_blocking_work_complete(struct suspend_blocking_work *work)
+{
+	unsigned long flags;
+
+	WARN_ON(!work->active);
+	spin_lock_irqsave(&work->lock, flags);
+	if (!--work->active)
+		suspend_unblock(&work->suspend_blocker);
+	spin_unlock_irqrestore(&work->lock, flags);
+}
+
+static void suspend_blocking_work_func(struct work_struct *work)
+{
+	struct suspend_blocking_work *sbwork = to_suspend_blocking_work(work);
+
+	sbwork->func(work);
+	suspend_blocking_work_complete(sbwork);
+}
+
+/**
+ * suspend_blocking_work_init - Initialize suspend_blocking_work
+ * @work: The work item in question.
+ * @func: Callback.
+ * @name: Name for suspend blocker.
+ *
+ */
+void suspend_blocking_work_init(struct suspend_blocking_work *work,
+				work_func_t func, const char *name)
+{
+	INIT_WORK(&work->work, suspend_blocking_work_func);
+	suspend_blocker_init(&work->suspend_blocker, name);
+	work->func = func;
+	spin_lock_init(&work->lock);
+	work->active = 0;
+}
+EXPORT_SYMBOL_GPL(suspend_blocking_work_init);
+
+/**
+ * cancel_suspend_blocking_work_sync - Cancel suspend_blocking_work
+ * @work: The work item in question
+ */
+int cancel_suspend_blocking_work_sync(struct suspend_blocking_work *work)
+{
+	int ret;
+
+	ret = cancel_work_sync(&work->work);
+	if (ret)
+		suspend_blocking_work_complete(work);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cancel_suspend_blocking_work_sync);
+
+/**
+ * suspend_blocking_work_destroy - Destroy suspend_blocking_work
+ * @work: The work item in question
+ *
+ * If the work was ever queued on more then one workqueue all but the last
+ * workqueue must be flushed before calling suspend_blocking_work_destroy.
+ */
+void suspend_blocking_work_destroy(struct suspend_blocking_work *work)
+{
+	cancel_suspend_blocking_work_sync(work);
+	WARN_ON(work->active);
+	suspend_blocker_destroy(&work->suspend_blocker);
+}
+EXPORT_SYMBOL_GPL(suspend_blocking_work_destroy);
+
+/**
+ * queue_suspend_blocking_work - Queue suspend blocking work
+ * @wq:		Workqueue to queue work on.
+ * @work:	The work item in question.
+ */
+int queue_suspend_blocking_work(struct workqueue_struct *wq,
+				struct suspend_blocking_work *work)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&work->lock, flags);
+	ret = queue_work(wq, &work->work);
+	if (ret) {
+		suspend_block(&work->suspend_blocker);
+		work->active++;
+	}
+	spin_unlock_irqrestore(&work->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(queue_suspend_blocking_work);
+
+/**
+ * schedule_suspend_blocking_work - Queue suspend blocking work
+ * @work:	The work item in question.
+ */
+int schedule_suspend_blocking_work(struct suspend_blocking_work *work)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&work->lock, flags);
+	ret = schedule_work(&work->work);
+	if (ret) {
+		suspend_block(&work->suspend_blocker);
+		work->active++;
+	}
+	spin_unlock_irqrestore(&work->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(schedule_suspend_blocking_work);
-- 
1.6.5.1

--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 0/8] Suspend block api (version 6), =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 1/8] PM: Add suspend block api., =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 2/8] PM: suspend_block: Add driver to access suspen ..., =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 3/8] PM: suspend_block: Abort task freezing if a su ..., =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 4/8] PM: suspend_block: Add debugfs file, =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 5/8] PM: suspend_block: Add suspend_blocker stats, =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 6/8] PM: Add suspend blocking work., =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:36 pm)
[PATCH 7/8] Input: Block suspend while event queue is not ..., =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:37 pm)
[PATCH 8/8] power_supply: Block suspend while power supply ..., =?UTF-8?q?Arve=20Hj= ..., (Fri Apr 30, 3:37 pm)
Re: [PATCH 6/8] PM: Add suspend blocking work., Tejun Heo, (Fri Apr 30, 11:14 pm)
Re: [PATCH 1/8] PM: Add suspend block api., Pavel Machek, (Sat May 1, 11:56 pm)
Re: [PATCH 1/8] PM: Add suspend block api., Pavel Machek, (Sun May 2, 12:01 am)
Re: [PATCH 6/8] PM: Add suspend blocking work., Pavel Machek, (Sun May 2, 12:05 am)
Re: [PATCH 1/8] PM: Add suspend block api., Rafael J. Wysocki, (Sun May 2, 1:10 pm)
Re: [PATCH 1/8] PM: Add suspend block api., Pavel Machek, (Sun May 2, 1:52 pm)
Re: [PATCH 1/8] PM: Add suspend block api., Rafael J. Wysocki, (Sun May 2, 2:29 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Mon May 3, 9:40 am)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Mon May 3, 11:07 am)
Re: [PATCH 1/8] PM: Add suspend block api., Pavel Machek, (Mon May 3, 12:01 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Mon May 3, 2:18 pm)
Re: [PATCH 1/8] PM: Add suspend block api., Rafael J. Wysocki, (Mon May 3, 2:38 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Mon May 3, 2:50 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Mon May 3, 4:37 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Arve Hjønnevåg, (Mon May 3, 5:09 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Mon May 3, 5:43 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Mon May 3, 5:43 pm)
Re: [PATCH 4/8] PM: suspend_block: Add debugfs file, Andi Kleen, (Tue May 4, 4:16 am)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Tue May 4, 6:59 am)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Tue May 4, 8:13 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Tue May 4, 8:28 am)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Tue May 4, 11:04 am)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Tue May 4, 11:06 am)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Tue May 4, 12:06 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Tue May 4, 1:23 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Tue May 4, 1:37 pm)
Re: [linux-pm] [PATCH 1/8] PM: Add suspend block api., Arve Hjønnevåg, (Tue May 4, 1:40 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Tue May 4, 1:44 pm)
Re: [PATCH 4/8] PM: suspend_block: Add debugfs file, Arve Hjønnevåg, (Tue May 4, 2:06 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Tue May 4, 4:14 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Tue May 4, 4:42 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Tue May 4, 4:56 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Tue May 4, 5:22 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Tue May 4, 6:11 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Wed May 5, 4:06 am)
Re: [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Wed May 5, 5:00 am)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Wed May 5, 6:56 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Wed May 5, 10:33 am)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Wed May 5, 11:39 am)
Re: [PATCH 0/8] Suspend block api (version 6), mark gross, (Wed May 5, 1:35 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Kevin Hilman, (Mon May 10, 11:06 am)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Mon May 10, 1:25 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Tony Lindgren, (Tue May 11, 9:12 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Tue May 11, 9:14 am)
Re: [PATCH 0/8] Suspend block api (version 6), Tony Lindgren, (Tue May 11, 9:36 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Tue May 11, 9:45 am)
Re: [PATCH 0/8] Suspend block api (version 6), Tony Lindgren, (Tue May 11, 9:58 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Tue May 11, 10:03 am)
Re: [PATCH 0/8] Suspend block api (version 6), Tony Lindgren, (Tue May 11, 10:24 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Tue May 11, 10:30 am)
Re: [PATCH 0/8] Suspend block api (version 6), Tony Lindgren, (Tue May 11, 10:48 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Tue May 11, 11:01 am)
Re: [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Tue May 11, 11:19 am)
Re: [PATCH 0/8] Suspend block api (version 6), Arve Hjønnevåg, (Tue May 11, 6:11 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Mark Brown, (Wed May 12, 4:22 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Paul Walmsley, (Wed May 12, 8:35 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Thu May 13, 5:17 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Thu May 13, 10:33 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Thu May 13, 11:17 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Thu May 13, 11:25 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Thu May 13, 11:36 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Thu May 13, 11:59 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Thu May 13, 12:11 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Thu May 13, 12:36 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Thu May 13, 12:48 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Thu May 13, 2:11 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Thu May 13, 2:16 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Thu May 13, 2:27 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Thu May 13, 2:33 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Tony Lindgren, (Thu May 13, 2:36 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Thu May 13, 2:54 pm)
RE: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Woodruff, Richard, (Thu May 13, 3:33 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Rafael J. Wysocki, (Thu May 13, 3:46 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Arve Hjønnevåg, (Thu May 13, 4:06 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Thu May 13, 4:28 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Thu May 13, 4:48 pm)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Daniel Walker, (Fri May 14, 9:47 am)
Re: [linux-pm] [PATCH 0/8] Suspend block api (version 6), Brian Swetland, (Mon May 17, 4:04 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Pavel Machek, (Mon May 24, 11:57 am)
Re: [PATCH 0/8] Suspend block api (version 6), Matthew Garrett, (Mon May 24, 12:08 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Arve Hjønnevåg, (Mon May 24, 6:16 pm)
Re: [PATCH 0/8] Suspend block api (version 6), Pavel Machek, (Wed May 26, 10:32 am)