public inbox for linux-pm@vger.kernel.org
 help / color / mirror / Atom feed
From: "Arve Hjønnevåg" <arve@android.com>
To: linux-pm@lists.linux-foundation.org, linux-kernel@vger.kernel.org
Cc: Len Brown <len.brown@intel.com>, Oleg Nesterov <oleg@redhat.com>,
	Tejun Heo <tj@kernel.org>
Subject: [PATCH 6/8] PM: Add suspend blocking work.
Date: Tue, 27 Apr 2010 21:31:57 -0700	[thread overview]
Message-ID: <1272429119-12103-7-git-send-email-arve@android.com> (raw)
In-Reply-To: <1272429119-12103-6-git-send-email-arve@android.com>

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  |  107 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 174 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 2d43f37..f9c6206 100644
--- a/kernel/power/suspend_blocker.c
+++ b/kernel/power/suspend_blocker.c
@@ -484,3 +484,110 @@ static int __init suspend_block_postcore_init(void)
 
 core_initcall(suspend_block_init);
 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(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(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(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);
+	suspend_block(&work->suspend_blocker);
+	ret = queue_work(wq, &work->work);
+	if (ret)
+		work->active++;
+	spin_unlock_irqrestore(&work->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(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);
+	suspend_block(&work->suspend_blocker);
+	ret = schedule_work(&work->work);
+	if (ret)
+		work->active++;
+	spin_unlock_irqrestore(&work->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(schedule_suspend_blocking_work);
-- 
1.6.5.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

  reply	other threads:[~2010-04-28  4:31 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1272429119-12103-1-git-send-email-arve@android.com>
2010-04-28  4:31 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
     [not found] ` <1272429119-12103-2-git-send-email-arve@android.com>
2010-04-28  4:31   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-28  4:31     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-04-28  4:31       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-04-28  4:31         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-04-28  4:31           ` Arve Hjønnevåg [this message]
2010-04-28  4:31             ` [PATCH 7/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
2010-04-28  4:31               ` [PATCH 8/8] power_supply: Block suspend while power supply change notifications are pending Arve Hjønnevåg
2010-04-28  6:06             ` [PATCH 6/8] PM: Add suspend blocking work Pavel Machek
2010-04-28  6:44             ` Tejun Heo
2010-04-28  7:02               ` Arve Hjønnevåg
     [not found]               ` <i2vd6200be21004280002tde778c02h1586b4c06de2a89a@mail.gmail.com>
2010-04-28  7:18                 ` Tejun Heo
2010-04-28 19:40             ` Oleg Nesterov
     [not found]             ` <20100428194028.GA16389@redhat.com>
2010-04-28 20:22               ` Tejun Heo
2010-04-28 21:08                 ` Rafael J. Wysocki
2010-04-29 18:58                   ` Oleg Nesterov
2010-04-29 19:44                     ` [PATCH 0/2] workqueue fixlets (Was: PM: Add suspend blocking work.) Oleg Nesterov
2010-04-29 19:45                       ` [PATCH 1/2] workqueues: flush_delayed_work: keep the original workqueue for re-queueing Oleg Nesterov
2010-04-30  5:15                         ` Tejun Heo
2010-04-29 19:45                       ` [PATCH 2/2] workqueues: export keventd_wq Oleg Nesterov
2010-04-30  5:16                         ` Tejun Heo
2010-04-30  5:39                           ` Arve Hjønnevåg
2010-04-30  5:52                             ` Tejun Heo
2010-04-30 18:05                               ` Oleg Nesterov
2010-04-30 18:11                                 ` Tejun Heo
2010-04-29 21:08                     ` [PATCH 6/8] PM: Add suspend blocking work Rafael J. Wysocki
2010-04-28 21:09               ` Rafael J. Wysocki
2010-04-28 22:09                 ` Arve Hjønnevåg
     [not found]                 ` <x2id6200be21004281509j84c29664m60068e7bfc86f64f@mail.gmail.com>
2010-04-28 22:19                   ` Rafael J. Wysocki
     [not found]                   ` <201004290019.26381.rjw@sisk.pl>
2010-04-29  3:47                     ` Arve Hjønnevåg
     [not found]                     ` <s2rd6200be21004282047qc1b88ac5h1759f22f3c16ce85@mail.gmail.com>
2010-04-29 21:09                       ` Rafael J. Wysocki
2010-04-28  5:07       ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Pavel Machek
2010-04-28 20:58     ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Rafael J. Wysocki
     [not found]     ` <201004282258.51354.rjw@sisk.pl>
2010-04-28 22:31       ` Arve Hjønnevåg
     [not found]       ` <k2gd6200be21004281531y270549d7g8383f2c8a55038d4@mail.gmail.com>
2010-04-28 23:05         ` Rafael J. Wysocki
     [not found]         ` <201004290105.15707.rjw@sisk.pl>
2010-04-28 23:38           ` Arve Hjønnevåg
     [not found]           ` <h2jd6200be21004281638y6b751abesfcf6416707e6fee4@mail.gmail.com>
2010-04-29 21:11             ` Rafael J. Wysocki
2010-04-29 23:41               ` Arve Hjønnevåg
2010-04-28  6:07   ` [PATCH 1/8] PM: Add suspend block api Pavel Machek
2010-04-28 19:13   ` Alan Stern
2010-04-28 20:50   ` Rafael J. Wysocki
     [not found]   ` <201004282250.44200.rjw@sisk.pl>
2010-04-29  3:37     ` Arve Hjønnevåg
     [not found]     ` <l2yd6200be21004282037rc063266by91db7f732ceaa529@mail.gmail.com>
2010-04-29 21:16       ` Rafael J. Wysocki
2010-04-30  4:24         ` Tejun Heo
2010-04-30 17:26           ` Oleg Nesterov
     [not found]           ` <20100430172618.GA9043@redhat.com>
2010-05-20  8:30             ` Tejun Heo
     [not found]             ` <4BF4F31D.8070900@kernel.org>
2010-05-20 22:27               ` Rafael J. Wysocki
     [not found]               ` <201005210027.31910.rjw@sisk.pl>
2010-05-21  6:35                 ` Tejun Heo
2010-05-06 15:18   ` Alan Stern
     [not found] <1272667021-21312-1-git-send-email-arve@android.com>
     [not found] ` <1272667021-21312-2-git-send-email-arve@android.com>
2010-04-30 22:36   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-30 22:36     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-04-30 22:36       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-04-30 22:36         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-04-30 22:36           ` [PATCH 6/8] PM: Add suspend blocking work Arve Hjønnevåg
2010-05-01  6:14             ` Tejun Heo
2010-05-02  7:05             ` Pavel Machek
     [not found] <1273810273-3039-1-git-send-email-arve@android.com>
2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-05-14  4:11   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-05-14  4:11     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-05-14  4:11       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-05-14  4:11         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-05-14  4:11           ` [PATCH 6/8] PM: Add suspend blocking work Arve Hjønnevåg
     [not found] <1274482015-30899-1-git-send-email-arve@android.com>
     [not found] ` <1274482015-30899-2-git-send-email-arve@android.com>
     [not found]   ` <1274482015-30899-3-git-send-email-arve@android.com>
     [not found]     ` <1274482015-30899-4-git-send-email-arve@android.com>
     [not found]       ` <1274482015-30899-5-git-send-email-arve@android.com>
     [not found]         ` <1274482015-30899-6-git-send-email-arve@android.com>
2010-05-21 22:46           ` Arve Hjønnevåg

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=1272429119-12103-7-git-send-email-arve@android.com \
    --to=arve@android.com \
    --cc=len.brown@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=oleg@redhat.com \
    --cc=tj@kernel.org \
    /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
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox