Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 341a5958 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds
Browse files

[PATCH] Support for freezeable workqueues



Make it possible to create a workqueue the worker thread of which will be
frozen during suspend, along with other kernel threads.

Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Cc: Nigel Cunningham <nigel@suspend2.net>
Cc: David Chinner <dgc@sgi.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5045cfc1
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -147,9 +147,11 @@ struct execute_work {




extern struct workqueue_struct *__create_workqueue(const char *name,
extern struct workqueue_struct *__create_workqueue(const char *name,
						    int singlethread);
						    int singlethread,
#define create_workqueue(name) __create_workqueue((name), 0)
						    int freezeable);
#define create_singlethread_workqueue(name) __create_workqueue((name), 1)
#define create_workqueue(name) __create_workqueue((name), 0, 0)
#define create_freezeable_workqueue(name) __create_workqueue((name), 0, 1)
#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0)


extern void destroy_workqueue(struct workqueue_struct *wq);
extern void destroy_workqueue(struct workqueue_struct *wq);


+14 −6
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/hardirq.h>
#include <linux/hardirq.h>
#include <linux/mempolicy.h>
#include <linux/mempolicy.h>
#include <linux/freezer.h>


/*
/*
 * The per-CPU workqueue (if single thread, we always use the first
 * The per-CPU workqueue (if single thread, we always use the first
@@ -55,6 +56,8 @@ struct cpu_workqueue_struct {
	struct task_struct *thread;
	struct task_struct *thread;


	int run_depth;		/* Detect run_workqueue() recursion depth */
	int run_depth;		/* Detect run_workqueue() recursion depth */

	int freezeable;		/* Freeze the thread during suspend */
} ____cacheline_aligned;
} ____cacheline_aligned;


/*
/*
@@ -265,6 +268,7 @@ static int worker_thread(void *__cwq)
	struct k_sigaction sa;
	struct k_sigaction sa;
	sigset_t blocked;
	sigset_t blocked;


	if (!cwq->freezeable)
		current->flags |= PF_NOFREEZE;
		current->flags |= PF_NOFREEZE;


	set_user_nice(current, -5);
	set_user_nice(current, -5);
@@ -288,6 +292,9 @@ static int worker_thread(void *__cwq)


	set_current_state(TASK_INTERRUPTIBLE);
	set_current_state(TASK_INTERRUPTIBLE);
	while (!kthread_should_stop()) {
	while (!kthread_should_stop()) {
		if (cwq->freezeable)
			try_to_freeze();

		add_wait_queue(&cwq->more_work, &wait);
		add_wait_queue(&cwq->more_work, &wait);
		if (list_empty(&cwq->worklist))
		if (list_empty(&cwq->worklist))
			schedule();
			schedule();
@@ -364,7 +371,7 @@ void fastcall flush_workqueue(struct workqueue_struct *wq)
EXPORT_SYMBOL_GPL(flush_workqueue);
EXPORT_SYMBOL_GPL(flush_workqueue);


static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
						   int cpu)
						   int cpu, int freezeable)
{
{
	struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
	struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
	struct task_struct *p;
	struct task_struct *p;
@@ -374,6 +381,7 @@ static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
	cwq->thread = NULL;
	cwq->thread = NULL;
	cwq->insert_sequence = 0;
	cwq->insert_sequence = 0;
	cwq->remove_sequence = 0;
	cwq->remove_sequence = 0;
	cwq->freezeable = freezeable;
	INIT_LIST_HEAD(&cwq->worklist);
	INIT_LIST_HEAD(&cwq->worklist);
	init_waitqueue_head(&cwq->more_work);
	init_waitqueue_head(&cwq->more_work);
	init_waitqueue_head(&cwq->work_done);
	init_waitqueue_head(&cwq->work_done);
@@ -389,7 +397,7 @@ static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
}
}


struct workqueue_struct *__create_workqueue(const char *name,
struct workqueue_struct *__create_workqueue(const char *name,
					    int singlethread)
					    int singlethread, int freezeable)
{
{
	int cpu, destroy = 0;
	int cpu, destroy = 0;
	struct workqueue_struct *wq;
	struct workqueue_struct *wq;
@@ -409,7 +417,7 @@ struct workqueue_struct *__create_workqueue(const char *name,
	mutex_lock(&workqueue_mutex);
	mutex_lock(&workqueue_mutex);
	if (singlethread) {
	if (singlethread) {
		INIT_LIST_HEAD(&wq->list);
		INIT_LIST_HEAD(&wq->list);
		p = create_workqueue_thread(wq, singlethread_cpu);
		p = create_workqueue_thread(wq, singlethread_cpu, freezeable);
		if (!p)
		if (!p)
			destroy = 1;
			destroy = 1;
		else
		else
@@ -417,7 +425,7 @@ struct workqueue_struct *__create_workqueue(const char *name,
	} else {
	} else {
		list_add(&wq->list, &workqueues);
		list_add(&wq->list, &workqueues);
		for_each_online_cpu(cpu) {
		for_each_online_cpu(cpu) {
			p = create_workqueue_thread(wq, cpu);
			p = create_workqueue_thread(wq, cpu, freezeable);
			if (p) {
			if (p) {
				kthread_bind(p, cpu);
				kthread_bind(p, cpu);
				wake_up_process(p);
				wake_up_process(p);
@@ -667,7 +675,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
		mutex_lock(&workqueue_mutex);
		mutex_lock(&workqueue_mutex);
		/* Create a new workqueue thread for it. */
		/* Create a new workqueue thread for it. */
		list_for_each_entry(wq, &workqueues, list) {
		list_for_each_entry(wq, &workqueues, list) {
			if (!create_workqueue_thread(wq, hotcpu)) {
			if (!create_workqueue_thread(wq, hotcpu, 0)) {
				printk("workqueue for %i failed\n", hotcpu);
				printk("workqueue for %i failed\n", hotcpu);
				return NOTIFY_BAD;
				return NOTIFY_BAD;
			}
			}