[PATCH 1/2] workqueues: flush_delayed_work: keep the original workqueue for re-queueing

Previous thread: [PATCH] sched: use wrapper functions by Changli Gao on Tuesday, April 27, 2010 - 8:43 pm. (1 message)

Next thread: [PATCH/RFC] mutex: Fix optimistic spinning vs. BKL by Benjamin Herrenschmidt on Tuesday, April 27, 2010 - 9:38 pm. (20 messages)
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

This patch series adds a suspend-block api that provides the same
functionality as the android wakelock api. The main change from
version 4 posted last week is that suspend blocking work has moved out
of the core workqueue code. The documentation has also been updated.

--
Arve Hjønnevåg <arve@android.com>

--

From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

Adds /sys/power/policy that selects the behaviour of /sys/power/state.
After setting the policy to opportunistic, writes to /sys/power/state
become non-blocking requests that specify which suspend state to enter
when no suspend blockers are active. A special state, "on", stops the
process by activating the "main" suspend blocker.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/power/opportunistic-suspend.txt |  114 +++++++++++
 include/linux/suspend_blocker.h               |   64 ++++++
 kernel/power/Kconfig                          |   16 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/main.c                           |   89 ++++++++-
 kernel/power/power.h                          |    5 +
 kernel/power/suspend.c                        |    4 +-
 kernel/power/suspend_blocker.c                |  269 +++++++++++++++++++++++++
 8 files changed, 556 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/power/opportunistic-suspend.txt
 create mode 100755 include/linux/suspend_blocker.h
 create mode 100644 kernel/power/suspend_blocker.c

diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
new file mode 100644
index 0000000..1a29d10
--- /dev/null
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -0,0 +1,114 @@
+Opportunistic Suspend
+=====================
+
+Opportunistic suspend is a feature allowing the system to be suspended (ie. put
+into one of the available sleep states) automatically whenever it is regarded
+as idle.  The suspend blockers framework described below is used to determine
+when that happens.
+
+The /sys/power/policy sysfs attribute is used to switch the system between the
+opportunistic and "forced" suspend behavior, where in the latter case the
+system is only suspended if a specific value, corresponding to one of the
+available system sleep states, is written into /sys/power/state.  However, in
+the former, opportunistic, case the system is ...
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

Report active and inactive suspend blockers in
/sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 kernel/power/suspend_blocker.c |   44 ++++++++++++++++++++++++++++++++++++++-
 1 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/kernel/power/suspend_blocker.c b/kernel/power/suspend_blocker.c
index 9459361..ee43490 100644
--- a/kernel/power/suspend_blocker.c
+++ b/kernel/power/suspend_blocker.c
@@ -17,6 +17,7 @@
 #include <linux/rtc.h>
 #include <linux/suspend.h>
 #include <linux/suspend_blocker.h>
+#include <linux/debugfs.h>
 #include "power.h"
 
 enum {
@@ -41,6 +42,7 @@ struct workqueue_struct *suspend_work_queue;
 struct suspend_blocker main_suspend_blocker;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
+static struct dentry *suspend_blocker_stats_dentry;
 
 #define pr_info_time(fmt, args...) \
 	do { \
@@ -54,6 +56,21 @@ static bool enable_suspend_blockers;
 			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
 	} while (0);
 
+static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+
+	seq_puts(m, "name\tactive\n");
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_for_each_entry(blocker, &inactive_blockers, link)
+		seq_printf(m, "\"%s\"\t0\n", blocker->name);
+	list_for_each_entry(blocker, &active_blockers, link)
+		seq_printf(m, "\"%s\"\t1\n", blocker->name);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return 0;
+}
+
 static void print_active_blockers_locked(void)
 {
 	struct suspend_blocker *blocker;
@@ -105,8 +122,8 @@ static DECLARE_WORK(suspend_work, suspend_worker);
 /**
  * suspend_blocker_init() - Initialize a suspend blocker
  * @blocker:	The suspend blocker to initialize.
- * @name:	The name of the suspend blocker to show in debug messages.
- *
+ * @name:	The name of the suspend blocker to show in debug messages and
+ ...
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

Report suspend block stats in /sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_blocker.h |   21 ++++-
 kernel/power/Kconfig            |    7 ++
 kernel/power/power.h            |    6 +-
 kernel/power/suspend.c          |    4 +-
 kernel/power/suspend_blocker.c  |  191 +++++++++++++++++++++++++++++++++++++--
 5 files changed, 219 insertions(+), 10 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index f9928cc..c80764c 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -17,12 +17,21 @@
 #define _LINUX_SUSPEND_BLOCKER_H
 
 #include <linux/list.h>
+#include <linux/ktime.h>
 
 /**
  * struct suspend_blocker - the basic suspend_blocker structure
  * @link:	List entry for active or inactive list.
- * @flags:	Tracks initialized and active state.
+ * @flags:	Tracks initialized, active and stats state.
  * @name:	Name used for debugging.
+ * @count:	Number of times this blocker has been deacivated
+ * @wakeup_count: Number of times this blocker was the first to block suspend
+ *		after resume.
+ * @total_time:	Total time this suspend blocker has prevented suspend.
+ * @prevent_suspend_time: Time this suspend blocker has prevented suspend while
+ *		user-space requested suspend.
+ * @max_time:	Max time this suspend blocker has been continuously active
+ * @last_time:	Monotonic clock when the active state last changed.
  *
  * When a suspend_blocker is active it prevents the system from entering
  * opportunistic suspend.
@@ -35,6 +44,16 @@ struct suspend_blocker {
 	struct list_head    link;
 	int                 flags;
 	const char         *name;
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	struct {
+		int             count;
+		int             wakeup_count;
+		ktime_t         total_time;
+		ktime_t         prevent_suspend_time;
+		ktime_t         max_time;
+		ktime_t         last_time;
+	} stat;
+#endif
 #endif
 };
 
diff --git ...
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 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  |  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 ...
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

When connecting usb or the charger the device would often go back to sleep
before the charge led and screen turned on.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 drivers/power/power_supply_core.c |    9 ++++++---
 include/linux/power_supply.h      |    3 ++-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index cce75b4..577a131 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -39,7 +39,7 @@ static int __power_supply_changed_work(struct device *dev, void *data)
 static void power_supply_changed_work(struct work_struct *work)
 {
 	struct power_supply *psy = container_of(work, struct power_supply,
-						changed_work);
+						changed_work.work);
 
 	dev_dbg(psy->dev, "%s\n", __func__);
 
@@ -55,7 +55,7 @@ void power_supply_changed(struct power_supply *psy)
 {
 	dev_dbg(psy->dev, "%s\n", __func__);
 
-	schedule_work(&psy->changed_work);
+	schedule_suspend_blocking_work(&psy->changed_work);
 }
 EXPORT_SYMBOL_GPL(power_supply_changed);
 
@@ -155,7 +155,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 		goto dev_create_failed;
 	}
 
-	INIT_WORK(&psy->changed_work, power_supply_changed_work);
+	suspend_blocking_work_init(&psy->changed_work,
+				   power_supply_changed_work, "power-supply");
 
 	rc = power_supply_create_attrs(psy);
 	if (rc)
@@ -172,6 +173,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 create_triggers_failed:
 	power_supply_remove_attrs(psy);
 create_attrs_failed:
+	suspend_blocking_work_destroy(&psy->changed_work);
 	device_unregister(psy->dev);
 dev_create_failed:
 success:
@@ -184,6 +186,7 @@ void power_supply_unregister(struct power_supply *psy)
 	flush_scheduled_work();
 	power_supply_remove_triggers(psy);
 	power_supply_remove_attrs(psy);
+	suspend_blocking_work_destroy(&psy->changed_work);
 	device_unregister(psy->dev);
 }
 ...
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

Add an ioctl, EVIOCSSUSPENDBLOCK, to enable a suspend_blocker that will block
suspend while the event queue is not empty. This allows userspace code to
process input events while the device appears to be asleep.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 drivers/input/evdev.c |   22 ++++++++++++++++++++++
 include/linux/input.h |    3 +++
 2 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 2ee6c7a..66e0d16 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/major.h>
 #include <linux/device.h>
+#include <linux/suspend_blocker.h>
 #include "input-compat.h"
 
 struct evdev {
@@ -43,6 +44,8 @@ struct evdev_client {
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
 	struct list_head node;
+	struct suspend_blocker suspend_blocker;
+	bool use_suspend_blocker;
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -55,6 +58,8 @@ static void evdev_pass_event(struct evdev_client *client,
 	 * Interrupts are disabled, just acquire the lock
 	 */
 	spin_lock(&client->buffer_lock);
+	if (client->use_suspend_blocker)
+		suspend_block(&client->suspend_blocker);
 	client->buffer[client->head++] = *event;
 	client->head &= EVDEV_BUFFER_SIZE - 1;
 	spin_unlock(&client->buffer_lock);
@@ -234,6 +239,8 @@ static int evdev_release(struct inode *inode, struct file *file)
 	mutex_unlock(&evdev->mutex);
 
 	evdev_detach_client(evdev, client);
+	if (client->use_suspend_blocker)
+		suspend_blocker_destroy(&client->suspend_blocker);
 	kfree(client);
 
 	evdev_close_device(evdev);
@@ -335,6 +342,8 @@ static int evdev_fetch_next_event(struct evdev_client *client,
 	if (have_event) {
 		*event = client->buffer[client->tail++];
 		client->tail &= EVDEV_BUFFER_SIZE - 1;
+		if (client->use_suspend_blocker && client->head == client->tail)
+			suspend_unblock(&client->suspend_blocker);
 	}
 
 ...
From: Tejun Heo
Date: Tuesday, April 27, 2010 - 11:44 pm

As it's calling cancel_work_sync(), the above is not true.  As long as
no one is trying to queue it again, suspend_blocking_work_destroy() is

Other than the above, it looks good to me.

Thanks.

-- 
tejun
--

From: Arve Hjønnevåg
Date: Wednesday, April 28, 2010 - 12:02 am

I need the spinlock to prevent the work from getting re-queued before

I'm not sure what the best terminology is here, but cancel_work_sync()
only waits for work running on all the cpu-workqueues of the last
workqueue. So, if the caller queued the work on more than one
workqueue, suspend_blocking_work_destroy does not ensure that the
suspend_blocking_work structure is not still in use (it should trigger



-- 
Arve Hjønnevåg
--

From: Tejun Heo
Date: Wednesday, April 28, 2010 - 12:18 am

Hello,



Right, I was thinking about different cpu_workqueues and yeah, the
terminology gets pretty confusing.

Acked-by: Tejun Heo <tj@kernel.org>

Thanks.

-- 
tejun
--

From: Oleg Nesterov
Date: Wednesday, April 28, 2010 - 12:40 pm

I think this patch is fine.


why not

	ret = queue_work(wq, &work->work);
	if (ret) {
		suspend_block(&work->suspend_blocker);
		work->active++;
	}

?

Afaics, we can't race with work->func() doing unblock, we hold work-lock.
And this way the code looks more clear.

Sorry, I had no chance to read the previous patches. After the quick look
at 1/8 I think it is OK to call suspend_block() twice, but still...

Or I missed something? Just curious.


Hmm... actually, queue_work() can also fail if we race with cancel_ which
temporary sets WORK_STRUCT_PENDING. In that case suspend_block() won't

Off-topic. We should probably export keventd_wq to avoid the duplications
like this.

Oleg.

--

From: Tejun Heo
Date: Wednesday, April 28, 2010 - 1:22 pm

Yeah, had about the same thought.  cmwq exports it so I didn't suggest
it at this point but then again we don't really know whether or when
that series is going in so it might be a good idea to make that change
now.  Hmm...

Thanks.

-- 
tejun
--

From: Rafael J. Wysocki
Date: Wednesday, April 28, 2010 - 2:08 pm

I'd rather like a follow-up patch changing that, if poss.

Thanks,
Rafael
--

From: Oleg Nesterov
Date: Thursday, April 29, 2010 - 12:45 pm

flush_delayed_work() always uses keventd_wq for re-queueing,
but it should use the workqueue this dwork was queued on.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 kernel/workqueue.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- 34-rc1/kernel/workqueue.c~FDW_DONT_USE_KEVENT_WQ	2009-12-18 19:05:38.000000000 +0100
+++ 34-rc1/kernel/workqueue.c	2010-04-29 21:08:32.000000000 +0200
@@ -774,7 +774,7 @@ void flush_delayed_work(struct delayed_w
 {
 	if (del_timer_sync(&dwork->timer)) {
 		struct cpu_workqueue_struct *cwq;
-		cwq = wq_per_cpu(keventd_wq, get_cpu());
+		cwq = wq_per_cpu(get_wq_data(&dwork->work)->wq, get_cpu());
 		__queue_work(cwq, &dwork->work);
 		put_cpu();
 	}

--

From: Tejun Heo
Date: Thursday, April 29, 2010 - 10:15 pm

Hello,


Acked-by: Tejun Heo <tj@kernel.org>

I'll queue it through the wq tree I have.

Thanks.

-- 
tejun
--

From: Tejun Heo
Date: Thursday, April 29, 2010 - 10:16 pm

Hello,


Umm... does it have to be EXPORTed?  Suspend block API can't be built
as a module, right?

-- 
tejun
--

From: Arve Hjønnevåg
Date: Thursday, April 29, 2010 - 10:39 pm

The suspend block api cannot be built as a module, but if
schedule_suspend_blocking_work will just call
queue_suspend_blocking_work(keventd_wq, work) it may as well be an
inline function which would require the export.

-- 
Arve Hjønnevåg
--

From: Oleg Nesterov
Date: Friday, April 30, 2010 - 11:05 am

Right, but this allows to make schedule_xxx/flush_scheduled_work
inline and kill more EXPORT_SYMBOL's, and cmwq exports it anyway

But then schedule_suspend_blocking_work() in turn needs EXPORT_SYMBOL().


OK. Let's forget this patch. We can unify schedule_suspend_blocking_work
and queue_suspend_blocking_work later, or Arve can add this export into
his patch (without EXPORT_SYMBOL) - either way I agree. This is very
minor issue, I regret I originated this almost offtopic noise ;)

Oleg.

--

From: Tejun Heo
Date: Friday, April 30, 2010 - 11:11 am

Hello,



And, again, yeah, let's do it later.

Thanks.

-- 
tejun
--

From: Tejun Heo
Date: Thursday, April 29, 2010 - 10:52 pm

I think it would be better to keep the thing inside the kernel, at
least for now.  It's not like we need to save cpu cycles spent on a
function call here (in block suspend API and in workqueue general).

Thanks.

-- 
tejun
--

From: Rafael J. Wysocki
Date: Thursday, April 29, 2010 - 2:08 pm

No, I'm fine with the change itself, but I wouldn't like to make the suspend
blockers patchset depend on something in a different tree.  If it's not the
case, I have no objections.

Rafael
--

From: Oleg Nesterov
Date: Thursday, April 29, 2010 - 12:45 pm

Export keventd_wq. Otherwise, any helper on top of queue_work() has
to be copy-and-pasted to create the version which uses keventd_wq.

Note: we can do more cleanups with this change and kill EXPORT_SYMBOLs,
almost any function which currently uses keventd_wq can become the
trivial inline.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 include/linux/workqueue.h |    1 +
 kernel/workqueue.c        |    3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

--- 34-rc1/include/linux/workqueue.h~EXPORT_KEVENT_WQ	2009-12-18 19:05:38.000000000 +0100
+++ 34-rc1/include/linux/workqueue.h	2010-04-29 21:25:12.000000000 +0200
@@ -12,6 +12,7 @@
 #include <asm/atomic.h>
 
 struct workqueue_struct;
+extern struct workqueue_struct *keventd_wq;
 
 struct work_struct;
 typedef void (*work_func_t)(struct work_struct *work);
--- 34-rc1/kernel/workqueue.c~EXPORT_KEVENT_WQ	2010-04-29 21:08:32.000000000 +0200
+++ 34-rc1/kernel/workqueue.c	2010-04-29 21:23:46.000000000 +0200
@@ -717,7 +717,8 @@ int cancel_delayed_work_sync(struct dela
 }
 EXPORT_SYMBOL(cancel_delayed_work_sync);
 
-static struct workqueue_struct *keventd_wq __read_mostly;
+struct workqueue_struct *keventd_wq __read_mostly;
+EXPORT_SYMBOL(keventd_wq);
 
 /**
  * schedule_work - put work task in global workqueue

--

From: Oleg Nesterov
Date: Thursday, April 29, 2010 - 12:44 pm

So. I'd suggestd these 2 simple patches for now.

Please note that 2/2 is really trivial, it only adds EXPORT_SYMBOL but
avoids the possible cleanups to minimize the conflicts with the pending
cmwq changes. However, please feel free to ignore this patch.

As for 1/2, imho it is always better to fix the bug asap, even if it is
minor.

Oleg.

--

From: Oleg Nesterov
Date: Thursday, April 29, 2010 - 11:58 am

Confused. Rafael, do you mean you dislike this change now?

I don't really care, this change is trivial. But to me it makes more
sense to push the trivial/simple changes ahead. Unless they really
complicate the maintainging of the pending cmwq changes.

Hmm... Speaking about keventd_wq, I just noticed flush_delayed_work()
needs the fix:

	--- a/kernel/workqueue.c
	+++ b/kernel/workqueue.c
	@@ -774,7 +774,7 @@ void flush_delayed_work(struct delayed_w
	 {
		if (del_timer_sync(&dwork->timer)) {
			struct cpu_workqueue_struct *cwq;
	-		cwq = wq_per_cpu(keventd_wq, get_cpu());
	+		cwq = wq_per_cpu(get_wq_data(&dwork->work)->wq, get_cpu());
			__queue_work(cwq, &dwork->work);
			put_cpu();
		}

Oleg.

--

From: Rafael J. Wysocki
Date: Wednesday, April 28, 2010 - 2:09 pm

Please see my reply to Tejun. :-)

Rafael
--

From: Arve Hjønnevåg
Date: Wednesday, April 28, 2010 - 3:09 pm

I need to fix the race, but I can easily fix it in
cancel_suspend_blocking_work_sync instead. If the suspend blocker is
active for a long time, and DEBUG_SUSPEND_BLOCKER is enabled, we can



-- 
Arve Hjønnevåg
--

From: Rafael J. Wysocki
Date: Wednesday, April 28, 2010 - 3:19 pm

Well, perhaps that's worth adding a comment to the code.  The debug part is not
immediately visible from the code itself.

Rafael
--

From: Arve Hjønnevåg
Date: Wednesday, April 28, 2010 - 8:47 pm

On second thought, this only makes a difference if both conditions are
true. If we are constantly re-queuing the work but it is not stuck,
either method will show the debug message, so I used Oleg's
suggestion.

-- 
Arve Hjønnevåg
--

From: Rafael J. Wysocki
Date: Thursday, April 29, 2010 - 2:09 pm

OK, great.

Rafael
--

From: Pavel Machek
Date: Tuesday, April 27, 2010 - 11:06 pm

Cound we name it C_AUTO_SUSPEND... to reduce length and typo

Is the lock internal-use, or is API user allowed to use it?
								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--

From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

If a suspend_blocker is active, suspend will fail anyway. Since
try_to_freeze_tasks can take up to 20 seconds to complete or fail, aborting
as soon as someone blocks suspend (e.g. from an interrupt handler) improves
the worst case wakeup latency.

On an older kernel where task freezing could fail for processes attached
to a debugger, this fixed a problem where the device sometimes hung for
20 seconds before the screen turned on.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 kernel/power/process.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/kernel/power/process.c b/kernel/power/process.c
index 71ae290..d8ebd50 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -15,6 +15,7 @@
 #include <linux/syscalls.h>
 #include <linux/freezer.h>
 #include <linux/delay.h>
+#include <linux/suspend_blocker.h>
 
 /* 
  * Timeout for stopping processes
@@ -38,6 +39,7 @@ static int try_to_freeze_tasks(bool sig_only)
 	struct timeval start, end;
 	u64 elapsed_csecs64;
 	unsigned int elapsed_csecs;
+	bool wakeup = false;
 
 	do_gettimeofday(&start);
 
@@ -63,6 +65,10 @@ static int try_to_freeze_tasks(bool sig_only)
 				todo++;
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		if (todo && suspend_is_blocked()) {
+			wakeup = true;
+			break;
+		}
 		if (!todo || time_after(jiffies, end_time))
 			break;
 
@@ -85,13 +91,15 @@ static int try_to_freeze_tasks(bool sig_only)
 		 * but it cleans up leftover PF_FREEZE requests.
 		 */
 		printk("\n");
-		printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
+		printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
 				"(%d tasks refusing to freeze):\n",
+				wakeup ? "aborted" : "failed",
 				elapsed_csecs / 100, elapsed_csecs % 100, todo);
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			task_lock(p);
-			if (freezing(p) && !freezer_should_skip(p))
+			if (freezing(p) && !freezer_should_skip(p)
+					&& elapsed_csecs > ...
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?=
Date: Tuesday, April 27, 2010 - 9:31 pm

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   17 ++++
 include/linux/suspend_block_dev.h             |   25 +++++
 kernel/power/Kconfig                          |    9 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
 6 files changed, 182 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/suspend_block_dev.h
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 1a29d10..639da73 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -112,3 +112,20 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+User-space API
+==============
+
+To create a suspend_blocker from user-space, open the suspend_blocker device:
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+then call:
+    ioctl(fd, ...
From: Rafael J. Wysocki
Date: Wednesday, April 28, 2010 - 1:58 pm

Why is this not in a header?

Rafael
--

From: Arve Hjønnevåg
Date: Wednesday, April 28, 2010 - 3:31 pm

-- 
Arve Hjønnevåg
--

From: Rafael J. Wysocki
Date: Wednesday, April 28, 2010 - 4:05 pm

Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
sufficient.

BTW, I'd put parens around (debug_mask & DEBUG_FAILURE) for clarity.

Rafael
--

From: Arve Hjønnevåg
Date: Wednesday, April 28, 2010 - 4:38 pm

OK.

-- 
Arve Hjønnevåg
--

From: Rafael J. Wysocki
Date: Thursday, April 29, 2010 - 2:11 pm

Alternatively, you can add a new parameter for that, which I think I would prefer.

Rafael
--

From: Arve Hjønnevåg
Date: Thursday, April 29, 2010 - 4:41 pm

I use a bit-mask in the main suspend blocker code. This makes it easy
to turn on or off all the messages.

-- 
Arve Hjønnevåg
--

From: Rafael J. Wysocki
Date: Wednesday, April 28, 2010 - 1:50 pm

Would you mind if I changed the above so that "policy" doesn't even show up
if CONFIG_OPPORTUNISTIC_SUSPEND is unset?


Hmm, what exactly is this for?  It looks like a debug thing to me.  I'd use

Is there a strong objection to changing that (and the other instances below) to


Hmm.  Why don't you want to put that initialization into pm_init() (in
kernel/power/main.c)?

Also, we already have one PM workqueue.  It is used for runtime PM, but I guess
it may be used just as well for the opportunistic suspend.  It is freezable,
but would it hurt?

Rafael
--

From: Arve Hjønnevåg
Date: Wednesday, April 28, 2010 - 8:37 pm

2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
I don't mind, but It did not seem worth the trouble to hide it. It
will only list the supported policies, and it is easy to add or remove

If the driver that caused the wakeup does not use suspend blockers, we
the only choice is to try to suspend again. I want to know if this
happened. The stats patch disable this printk by default since it will
show up in the stats, and the timeout patch (not included here) delays
the retry.


I don't know if it is a strong objection, but I prefer that this api
is available to all drivers. I don't want to prevent a user from using
opportunistic suspend because a non-gpl driver could not use suspend
blockers. I changed the suspend blocking work functions to be gpl only
though, since they are not required, and the workqueue api is
available to gpl code anyway.



It was not needed before, but I changed pm_init to call

No, it works, the freezable flag is just ignored when I call
pm_suspend and I don't run anything else on the workqueue while
threads are frozen. It does need to be a single threaded workqueue
though, so make sure you don't just change that.

-- 
Arve Hjønnevåg
--

From: Tejun Heo
Date: Thursday, April 29, 2010 - 9:24 pm

Hello,


Rafael, can you elaborate a bit more on this?  Just in case I missed
something while doing cmwq as it currently doesn't have such limit.

Thanks.

-- 
tejun
--

From: Oleg Nesterov
Date: Friday, April 30, 2010 - 10:26 am

Currently _cpu_down() can't flush and/or stop the frozen cwq->thread.

IIRC this is fixable, but needs the nasty complications. We should
thaw + stop the frozen cwq->thread, then move the pending works to
another CPU.

Oleg.

--

From: Tejun Heo
Date: Thursday, May 20, 2010 - 1:30 am

Hello,

(sorry about late reply)


Oh, this isn't an issue w/ cmwq.  While frozen all new works are
collected into per-cpu delayed worklist and while frozen trustee in
charge of the cpu will keep waiting.  Once thawed, trustee will
execute all works including the delayed ones unbound to any cpu.

Thanks.

-- 
tejun
--

From: Rafael J. Wysocki
Date: Thursday, May 20, 2010 - 3:27 pm

So, does it require any intrusive changes to make it possible to create
multithread freezable workqueues?

Rafael
--

From: Tejun Heo
Date: Thursday, May 20, 2010 - 11:35 pm

Hello,


cmwq itself is quite intrusive changes but w/ cmwq it just takes
flipping a flag when creating the queue.

Thanks.

-- 
tejun
--

From: Rafael J. Wysocki
Date: Thursday, April 29, 2010 - 2:16 pm

Freezable workqueues have to be singlethread or else there will be unfixable
races, so you can safely assume things will stay as they are in this respect.


--

From: Pavel Machek
Date: Tuesday, April 27, 2010 - 11:07 pm

I really don't like how this changes semantics of 'state'. I guess I'd
prefer leaving state as is -- forced transition to hibernation while
system is set to opportunistically suspend seems sane -- and adding
something like

/sys/power/autosleep


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--

Previous thread: [PATCH] sched: use wrapper functions by Changli Gao on Tuesday, April 27, 2010 - 8:43 pm. (1 message)

Next thread: [PATCH/RFC] mutex: Fix optimistic spinning vs. BKL by Benjamin Herrenschmidt on Tuesday, April 27, 2010 - 9:38 pm. (20 messages)