Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
freezer.c
Go to the documentation of this file.
1 /*
2  * kernel/freezer.c - Function to freeze a process
3  *
4  * Originally from kernel/power/process.c
5  */
6 
7 #include <linux/interrupt.h>
8 #include <linux/suspend.h>
9 #include <linux/export.h>
10 #include <linux/syscalls.h>
11 #include <linux/freezer.h>
12 #include <linux/kthread.h>
13 
14 /* total number of freezing conditions in effect */
16 EXPORT_SYMBOL(system_freezing_cnt);
17 
18 /* indicate whether PM freezing is in effect, protected by pm_mutex */
21 
22 /* protects freezing and frozen transitions */
23 static DEFINE_SPINLOCK(freezer_lock);
24 
35 {
36  if (p->flags & PF_NOFREEZE)
37  return false;
38 
40  return true;
41 
42  if (pm_freezing && !(p->flags & PF_KTHREAD))
43  return true;
44 
45  return false;
46 }
48 
49 /* Refrigerator is place where frozen processes are stored :-). */
50 bool __refrigerator(bool check_kthr_stop)
51 {
52  /* Hmm, should we be allowed to suspend when there are realtime
53  processes around? */
54  bool was_frozen = false;
55  long save = current->state;
56 
57  pr_debug("%s entered refrigerator\n", current->comm);
58 
59  for (;;) {
61 
62  spin_lock_irq(&freezer_lock);
63  current->flags |= PF_FROZEN;
64  if (!freezing(current) ||
65  (check_kthr_stop && kthread_should_stop()))
66  current->flags &= ~PF_FROZEN;
67  spin_unlock_irq(&freezer_lock);
68 
69  if (!(current->flags & PF_FROZEN))
70  break;
71  was_frozen = true;
72  schedule();
73  }
74 
75  pr_debug("%s left refrigerator\n", current->comm);
76 
77  /*
78  * Restore saved task state before returning. The mb'd version
79  * needs to be used; otherwise, it might silently break
80  * synchronization which depends on ordered task state change.
81  */
82  set_current_state(save);
83 
84  return was_frozen;
85 }
87 
88 static void fake_signal_wake_up(struct task_struct *p)
89 {
90  unsigned long flags;
91 
92  if (lock_task_sighand(p, &flags)) {
93  signal_wake_up(p, 0);
94  unlock_task_sighand(p, &flags);
95  }
96 }
97 
109 bool freeze_task(struct task_struct *p)
110 {
111  unsigned long flags;
112 
113  spin_lock_irqsave(&freezer_lock, flags);
114  if (!freezing(p) || frozen(p)) {
115  spin_unlock_irqrestore(&freezer_lock, flags);
116  return false;
117  }
118 
119  if (!(p->flags & PF_KTHREAD)) {
120  fake_signal_wake_up(p);
121  /*
122  * fake_signal_wake_up() goes through p's scheduler
123  * lock and guarantees that TASK_STOPPED/TRACED ->
124  * TASK_RUNNING transition can't race with task state
125  * testing in try_to_freeze_tasks().
126  */
127  } else {
129  }
130 
131  spin_unlock_irqrestore(&freezer_lock, flags);
132  return true;
133 }
134 
135 void __thaw_task(struct task_struct *p)
136 {
137  unsigned long flags;
138 
139  /*
140  * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to
141  * be visible to @p as waking up implies wmb. Waking up inside
142  * freezer_lock also prevents wakeups from leaking outside
143  * refrigerator.
144  */
145  spin_lock_irqsave(&freezer_lock, flags);
146  if (frozen(p))
147  wake_up_process(p);
148  spin_unlock_irqrestore(&freezer_lock, flags);
149 }
150 
156 bool set_freezable(void)
157 {
158  might_sleep();
159 
160  /*
161  * Modify flags while holding freezer_lock. This ensures the
162  * freezer notices that we aren't frozen yet or the freezing
163  * condition is visible to try_to_freeze() below.
164  */
165  spin_lock_irq(&freezer_lock);
166  current->flags &= ~PF_NOFREEZE;
167  spin_unlock_irq(&freezer_lock);
168 
169  return try_to_freeze();
170 }