public inbox for linux-kernel@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: "Arve Hjønnevåg" <arve@android.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Dmitri Vorobiev" <dmitri.vorobiev@movial.com>,
	"Tejun Heo" <tj@kernel.org>, "Jiri Kosina" <jkosina@suse.cz>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Oleg Nesterov" <oleg@redhat.com>, "Ingo Molnar" <mingo@elte.hu>,
	"Andi Kleen" <ak@linux.intel.com>
Subject: [PATCH 7/9] PM: Add suspend blocking work.
Date: Thu, 22 Apr 2010 18:08:56 -0700	[thread overview]
Message-ID: <1271984938-13920-8-git-send-email-arve@android.com> (raw)
In-Reply-To: <1271984938-13920-7-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.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/workqueue.h |   45 ++++++++++++++++++++++++++++++++++++++++++++-
 kernel/workqueue.c        |   19 +++++++++++++++++++
 2 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 9466e86..9c5a078 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -9,6 +9,7 @@
 #include <linux/linkage.h>
 #include <linux/bitops.h>
 #include <linux/lockdep.h>
+#include <linux/suspend_blocker.h>
 #include <asm/atomic.h>
 
 struct workqueue_struct;
@@ -26,7 +27,8 @@ struct work_struct {
 	atomic_long_t data;
 #define WORK_STRUCT_PENDING 0		/* T if work item pending execution */
 #define WORK_STRUCT_STATIC  1		/* static initializer (debugobjects) */
-#define WORK_STRUCT_FLAG_MASK (3UL)
+#define WORK_STRUCT_SUSPEND_BLOCKING  2	/* suspend blocking work */
+#define WORK_STRUCT_FLAG_MASK (7UL)
 #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
 	struct list_head entry;
 	work_func_t func;
@@ -48,6 +50,23 @@ static inline struct delayed_work *to_delayed_work(struct work_struct *work)
 	return container_of(work, struct delayed_work, work);
 }
 
+struct suspend_blocking_work {
+	struct work_struct work;
+	struct suspend_blocker suspend_blocker;
+};
+
+static inline struct suspend_blocking_work *
+to_suspend_blocking_work(struct work_struct *work)
+{
+	return container_of(work, struct suspend_blocking_work, work);
+}
+
+static inline struct suspend_blocker *
+work_to_suspend_blocker(struct work_struct *work)
+{
+	return &to_suspend_blocking_work(work)->suspend_blocker;
+}
+
 struct execute_work {
 	struct work_struct work;
 };
@@ -157,6 +176,30 @@ static inline void destroy_work_on_stack(struct work_struct *work) { }
 		init_timer_deferrable(&(_work)->timer);		\
 	} while (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);
+	suspend_blocker_init(&work->suspend_blocker, name);
+	set_bit(WORK_STRUCT_SUSPEND_BLOCKING, work_data_bits(&work->work));
+}
+
+/**
+ * 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 or on a multithreaded
+ * workqueue all these workqueues must be flushed before calling
+ * suspend_blocking_work_destroy. If only a single singlethreaded workqueue
+ * was used flush_work or cancel_work_sync can be used instead.
+ */
+
+static inline void
+suspend_blocking_work_destroy(struct suspend_blocking_work *work)
+{
+	suspend_blocker_destroy(&work->suspend_blocker);
+}
+
 /**
  * work_pending - Find out whether a work item is currently pending
  * @work: The work item in question
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index dee4865..b2aba90 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -68,6 +68,15 @@ struct workqueue_struct {
 #endif
 };
 
+static inline int work_blocks_suspend(struct work_struct *work)
+{
+#ifdef CONFIG_SUSPEND_BLOCKERS
+	return test_bit(WORK_STRUCT_SUSPEND_BLOCKING, work_data_bits(work));
+#else
+	return false;
+#endif
+}
+
 #ifdef CONFIG_DEBUG_OBJECTS_WORK
 
 static struct debug_obj_descr work_debug_descr;
@@ -257,6 +266,10 @@ static void __queue_work(struct cpu_workqueue_struct *cwq,
 
 	debug_work_activate(work);
 	spin_lock_irqsave(&cwq->lock, flags);
+
+	if (work_blocks_suspend(work))
+		suspend_block(work_to_suspend_blocker(work));
+
 	insert_work(cwq, work, &cwq->worklist);
 	spin_unlock_irqrestore(&cwq->lock, flags);
 }
@@ -379,6 +392,7 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
 		struct work_struct *work = list_entry(cwq->worklist.next,
 						struct work_struct, entry);
 		work_func_t f = work->func;
+		bool current_work_blocks_suspend = work_blocks_suspend(work);
 #ifdef CONFIG_LOCKDEP
 		/*
 		 * It is permissible to free the struct work_struct
@@ -416,6 +430,9 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
 		}
 
 		spin_lock_irq(&cwq->lock);
+		if (current_work_blocks_suspend &&
+		    (get_wq_data(work) == cwq) && !work_pending(work))
+			suspend_unblock(work_to_suspend_blocker(work));
 		cwq->current_work = NULL;
 	}
 	spin_unlock_irq(&cwq->lock);
@@ -671,6 +688,8 @@ static int __cancel_work_timer(struct work_struct *work,
 		wait_on_work(work);
 	} while (unlikely(ret < 0));
 
+	if (work_blocks_suspend(work))
+		suspend_unblock(work_to_suspend_blocker(work));
 	work_clear_pending(work);
 	return ret;
 }
-- 
1.6.5.1


  reply	other threads:[~2010-04-23  1:10 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-04-23  1:08 [PATCH 0/9] Suspend block api (version 4) Arve Hjønnevåg
2010-04-23  1:08 ` [PATCH 1/9] PM: Add suspend block api Arve Hjønnevåg
2010-04-23  1:08   ` [PATCH 2/9] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-23  1:08     ` [PATCH 3/9] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-04-23  1:08       ` [PATCH 4/9] PM: suspend_block: Switch to list of active and inactive suspend blockers Arve Hjønnevåg
2010-04-23  1:08         ` [PATCH 5/9] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-04-23  1:08           ` [PATCH 6/9] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-04-23  1:08             ` Arve Hjønnevåg [this message]
2010-04-23  1:08               ` [PATCH 8/9] Input: Block suspend while event queue is not empty Arve Hjønnevåg
2010-04-23  1:08                 ` [PATCH 9/9] power_supply: Block suspend while power supply change notifications are pending Arve Hjønnevåg
2010-04-23 20:56                 ` [PATCH 8/9] Input: Block suspend while event queue is not empty Randy Dunlap
2010-04-23 21:08                   ` Dmitry Torokhov
2010-04-24  5:02                     ` Arve Hjønnevåg
2010-04-24 14:36                       ` [linux-pm] " Alan Stern
2010-04-25  2:30                         ` Rafael J. Wysocki
2010-04-25 15:29                           ` Alan Stern
2010-04-25 22:41                             ` Arve Hjønnevåg
2010-04-24  4:58                   ` Arve Hjønnevåg
2010-04-23  8:16               ` [PATCH 7/9] PM: Add suspend blocking work Tejun Heo
2010-04-23 12:20                 ` Oleg Nesterov
2010-04-23 22:49                   ` Arve Hjønnevåg
2010-04-24  5:21                     ` Arve Hjønnevåg
2010-04-24  6:33                     ` Tejun Heo
2010-04-24  7:21                       ` Arve Hjønnevåg
2010-04-24  7:43                         ` Tejun Heo
2010-04-26 14:06                     ` Oleg Nesterov
2010-04-23 20:58           ` [PATCH 5/9] PM: suspend_block: Add debugfs file Randy Dunlap
2010-04-24  3:23             ` Arve Hjønnevåg
2010-04-24  4:24               ` Randy Dunlap
2010-04-24  4:54                 ` Arve Hjønnevåg
2010-04-25 18:15             ` Greg KH
2010-04-25 19:53               ` Randy Dunlap
2010-04-26  0:00                 ` tytso
2010-04-26  0:23                   ` Randy Dunlap
2010-04-26  0:45                     ` tytso
2010-04-26  0:50                       ` Randy Dunlap
2010-04-26  1:39                     ` [linux-pm] " Alan Stern
2010-04-26  6:24                 ` Brian Swetland
2010-04-26 13:28                   ` Randy Dunlap
2010-04-23  2:25     ` [linux-pm] [PATCH 2/9] PM: suspend_block: Add driver to access suspend blockers from user-space Matt Helsley
2010-04-23  3:54       ` Arve Hjønnevåg
2010-04-23  4:38       ` Greg KH
2010-04-23  8:43     ` Pavel Machek
2010-04-23 16:43       ` [linux-pm] " Alan Stern
2010-04-24  3:20         ` Arve Hjønnevåg
2010-04-24  5:55           ` Pavel Machek
2010-04-24 14:44             ` Alan Stern
2010-04-25 22:34               ` Arve Hjønnevåg
2010-04-26 19:25                 ` Alan Stern
2010-04-27  4:04                   ` Arve Hjønnevåg
2010-04-27 18:33                     ` Alan Stern
2010-04-27 22:03                       ` Rafael J. Wysocki
2010-04-27 23:22                         ` Arve Hjønnevåg
2010-04-24  1:53       ` tytso
2010-04-24  5:39         ` Pavel Machek
2010-04-23 16:33   ` [PATCH 1/9] PM: Add suspend block api Alan Stern
2010-04-23 16:45     ` [linux-pm] " Alan Stern
2010-04-24  2:15     ` Arve Hjønnevåg
2010-04-24  2:30       ` Alan Stern
2010-04-24  3:14         ` Arve Hjønnevåg
2010-04-23  4:39 ` [linux-pm] [PATCH 0/9] Suspend block api (version 4) Greg KH

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=1271984938-13920-8-git-send-email-arve@android.com \
    --to=arve@android.com \
    --cc=ak@linux.intel.com \
    --cc=akpm@linux-foundation.org \
    --cc=dmitri.vorobiev@movial.com \
    --cc=jkosina@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=mingo@elte.hu \
    --cc=oleg@redhat.com \
    --cc=tglx@linutronix.de \
    --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