Re: [PATCH 2/4] Task notifier: Implement todo list in task_struct

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



(Sorry everyone else for emailing you too. I'm only doing so to honour
the convention of not removing people from replies.)

Hi Christoph.

As I look at the patch in preparation for sending it, I don't think I
really changed anything significant. (I didn't address the issues I
mentioned in the previous email).

The only thing I think might be worth mentioning is that I added
freeze_processes and thaw_processes declarations to
include/linux/suspend.h. I got warnings without them there - perhaps,
though, it's just due to differences in Suspend2.

Having said this, I promised to send you my version, so I've inlined it
below. As you'll see, I'm making some changes just to minimise the
differences with swsusp.

Regards,

Nigel

 Documentation/power/kernel_threads.txt |   10 +-
 Documentation/power/swsusp.txt         |    5 -
 include/linux/sched.h                  |    1 
 kernel/power/process.c                 |  114 ++++++++++++++++++---------------
 4 files changed, 72 insertions(+), 58 deletions(-)
diff -ruNp 992-suspend_fix.patch-old/Documentation/power/kernel_threads.txt 992-suspend_fix.patch-new/Documentation/power/kernel_threads.txt
--- 992-suspend_fix.patch-old/Documentation/power/kernel_threads.txt	2005-08-08 17:23:31.000000000 +1000
+++ 992-suspend_fix.patch-new/Documentation/power/kernel_threads.txt	2005-08-09 08:11:41.000000000 +1000
@@ -4,15 +4,15 @@ KERNEL THREADS
 Freezer
 
 Upon entering a suspended state the system will freeze all
-tasks. This is done by delivering pseudosignals. This affects
-kernel threads, too. To successfully freeze a kernel thread
-the thread has to check for the pseudosignal and enter the
-refrigerator. Code to do this looks like this:
+tasks. This is done by making all processes execute a notifier.
+This affects kernel threads, too. To successfully freeze a kernel thread
+the thread has to check for the notifications and call the notifier
+chain for the process. Code to do this looks like this:
 
 	do {
 		hub_events();
 		wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
-		try_to_freeze();
+		try_todo_list();
 	} while (!signal_pending(current));
 
 from drivers/usb/core/hub.c::hub_thread()
diff -ruNp 992-suspend_fix.patch-old/Documentation/power/swsusp.txt 992-suspend_fix.patch-new/Documentation/power/swsusp.txt
--- 992-suspend_fix.patch-old/Documentation/power/swsusp.txt	2005-08-08 17:23:31.000000000 +1000
+++ 992-suspend_fix.patch-new/Documentation/power/swsusp.txt	2005-08-09 08:11:41.000000000 +1000
@@ -155,7 +155,8 @@ should be sent to the mailing list avail
 website, and not to the Linux Kernel Mailing List. We are working
 toward merging suspend2 into the mainline kernel.
 
-Q: A kernel thread must voluntarily freeze itself (call 'refrigerator').
+Q: A kernel thread must work on the todo list (call 'run_todo_list')
+to enter the refrigerator.
 I found some kernel threads that don't do it, and they don't freeze
 so the system can't sleep. Is this a known behavior?
 
@@ -164,7 +165,7 @@ place where the thread is safe to be fro
 should be held at that point and it must be safe to sleep there), and
 add:
 
-       try_to_freeze();
+       try_todo_list();
 
 If the thread is needed for writing the image to storage, you should
 instead set the PF_NOFREEZE process flag when creating the thread (and
diff -ruNp 992-suspend_fix.patch-old/include/linux/sched.h 992-suspend_fix.patch-new/include/linux/sched.h
--- 992-suspend_fix.patch-old/include/linux/sched.h	2005-08-09 11:17:49.000000000 +1000
+++ 992-suspend_fix.patch-new/include/linux/sched.h	2005-08-09 08:11:41.000000000 +1000
@@ -835,7 +835,6 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_FLUSHER	0x00001000	/* responsible for disk writeback */
 #define PF_USED_MATH	0x00002000	/* if unset the fpu must be initialized before use */
-#define PF_FREEZE	0x00004000	/* this task is being frozen for suspend now */
 #define PF_NOFREEZE	0x00008000	/* this thread should not be frozen */
 #define PF_FROZEN	0x00010000	/* frozen for system suspend */
 #define PF_FSTRANS	0x00020000	/* inside a filesystem transaction */
diff -ruNp 992-suspend_fix.patch-old/kernel/power/process.c 992-suspend_fix.patch-new/kernel/power/process.c
--- 992-suspend_fix.patch-old/kernel/power/process.c	2005-08-09 11:17:48.000000000 +1000
+++ 992-suspend_fix.patch-new/kernel/power/process.c	2005-08-09 11:10:59.000000000 +1000
@@ -61,6 +61,11 @@ extern void suspend_relinquish_console(v
 static void freeze_lru(void);
 extern void thaw_lru(void);
 
+DECLARE_COMPLETION(kernelspace_thaw);
+DECLARE_COMPLETION(userspace_thaw);
+static atomic_t nr_userspace_frozen;
+static atomic_t nr_kernelspace_frozen;
+
 /*
  * to_be_frozen
  *
@@ -72,7 +77,7 @@ extern void thaw_lru(void);
 static int to_be_frozen(struct task_struct * p, int type_being_frozen) {
 
 	if ((p == current) ||
-	    (frozen(p)) ||
+	    (p->flags & PF_FROZEN) ||
 	    (p->flags & PF_NOFREEZE) ||
 	    (p->exit_state == EXIT_ZOMBIE) ||
 	    (p->exit_state == EXIT_DEAD) ||
@@ -86,47 +91,68 @@ static int to_be_frozen(struct task_stru
 	return 1;
 }
 
-/**
- * refrigerator - idle routine for frozen processes
- * @flag: unsigned long, non zero if signals to be flushed.
- *
- * A routine for kernel threads which should not do work during suspend
- * to enter and spin in until the process is finished.
+/*
+ * Invoked by the task todo list notifier when the task to be
+ * frozen is running.
  */
-
-void refrigerator(void)
+static int freeze_process(struct notifier_block *nl, unsigned long x, void *v)
 {
-	unsigned long flags;
+  	/* Hmm, should we be allowed to suspend when there are realtime
+  	   processes around? */
 	long save;
+
+	save = current->state;
+	current->flags |= PF_FROZEN;
+	notifier_chain_unregister(&current->todo, nl);
+	kfree(nl);
 	
-	spin_lock_irqsave(&current->sighand->siglock, flags);
+	spin_lock_irq(&current->sighand->siglock);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sighand->siglock, flags);
+	spin_unlock_irq(&current->sighand->siglock);
 
-	if (unlikely(current->flags & PF_NOFREEZE)) {
-		current->flags &= ~PF_FREEZE;
-		return;
+	if (current->mm) {
+		atomic_inc(&nr_userspace_frozen);
+		wait_for_completion(&userspace_thaw);
+		atomic_dec(&nr_userspace_frozen);
+	} else {
+		atomic_inc(&nr_kernelspace_frozen);
+		wait_for_completion(&kernelspace_thaw);
+		atomic_dec(&nr_kernelspace_frozen);
 	}
 
-	save = current->state;
-	suspend_message(SUSPEND_FREEZER, SUSPEND_VERBOSE, 0,
-		"\n%s (%d) refrigerated and sigpending recalculated.",
-		current->comm, current->pid);
+	current->flags &= ~PF_FROZEN;
+	current->state = save;
 
-	frozen_process(current);
+	return 0;
+}
 
-	while (test_suspend_state(SUSPEND_FREEZER_ON) && frozen(current)) {
-		current->state = TASK_STOPPED;
-		schedule();
-		spin_lock_irqsave(&current->sighand->siglock, flags);
-		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sighand->siglock, flags);
-	}
+static inline void freeze(struct task_struct *p)
+{
+	unsigned long flags;
+
+	/*
+	 * We only freeze if the todo list is empty to avoid
+	 * putting multiple freeze handlers on the todo list.
+	 */
 	
-	current->state = save;
-}
+	if (!p->todo) {
+		struct notifier_block *n;
 
+		n = kmalloc(sizeof(struct notifier_block),
+					GFP_ATOMIC);
+		if (n) {
+			n->notifier_call = freeze_process;
+			n->priority = 0;
+			notifier_chain_register(&p->todo, n);
+		}
+ 	}
 
+	/* Make the process work on its todo list */
+	spin_lock_irqsave(&p->sighand->siglock, flags);
+	recalc_sigpending();
+	signal_wake_up(p, 0);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+}
 
 /*
  * num_to_be_frozen
@@ -204,6 +230,12 @@ static int freeze_threads(int type, int 
 	unsigned long start_time = jiffies;
 	int result = 0, still_to_do;
 
+	if (!atomic_read(&nr_userspace_frozen))
+		init_completion(&userspace_thaw);
+	
+	if (!atomic_read(&nr_kernelspace_frozen))
+		init_completion(&kernelspace_thaw);
+
 	suspend_message(SUSPEND_FREEZER, SUSPEND_VERBOSE, 1,
 		"\n STARTING TO FREEZE TYPE %d THREADS.\n",
 		type);
@@ -388,7 +420,6 @@ aborting:
 
 void thaw_processes(int which_threads)
 {
-	struct task_struct *p, *g;
 	suspend_message(SUSPEND_FREEZER, SUSPEND_LOW, 1, "Thawing tasks\n");
 	
 	suspend_task = 0;
@@ -397,27 +428,10 @@ void thaw_processes(int which_threads)
 
 	clear_suspend_state(SUSPEND_DISABLE_SYNCING);
 	
-	preempt_disable();
-	
-	local_irq_disable();
+	complete_all(&kernelspace_thaw);
 
-	read_lock(&tasklist_lock);
-
-	do_each_thread(g, p) {
-		if (frozen(p)) {
-			if ((which_threads == FREEZER_KERNEL_THREADS) && p->mm)
-				continue;
-			suspend_message(SUSPEND_FREEZER, SUSPEND_VERBOSE, 0,
-					"Waking %5d: %s.\n", p->pid, p->comm);
-			thaw_process(p);
-		}
-	} while_each_thread(g, p);
-
-	read_unlock(&tasklist_lock);
-
-	preempt_enable();
-
-	local_irq_enable();
+	if (which_threads != FREEZER_KERNEL_THREADS)
+		complete_all(&userspace_thaw);
 
 	schedule();
 }


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux