Blame view
kernel/freezer.c
4.45 KB
8174f1503 container freezer... |
1 2 3 4 5 6 7 8 |
/* * kernel/freezer.c - Function to freeze a process * * Originally from kernel/power/process.c */ #include <linux/interrupt.h> #include <linux/suspend.h> |
9984de1a5 kernel: Map most ... |
9 |
#include <linux/export.h> |
8174f1503 container freezer... |
10 11 |
#include <linux/syscalls.h> #include <linux/freezer.h> |
8a32c441c freezer: implemen... |
12 |
#include <linux/kthread.h> |
8174f1503 container freezer... |
13 |
|
a3201227f freezer: make fre... |
14 15 16 17 18 19 20 |
/* total number of freezing conditions in effect */ atomic_t system_freezing_cnt = ATOMIC_INIT(0); EXPORT_SYMBOL(system_freezing_cnt); /* indicate whether PM freezing is in effect, protected by pm_mutex */ bool pm_freezing; bool pm_nosig_freezing; |
0c9af0926 freezer: use dedi... |
21 22 |
/* protects freezing and frozen transitions */ static DEFINE_SPINLOCK(freezer_lock); |
8174f1503 container freezer... |
23 |
|
a3201227f freezer: make fre... |
24 25 26 27 28 29 30 31 32 33 34 |
/** * freezing_slow_path - slow path for testing whether a task needs to be frozen * @p: task to be tested * * This function is called by freezing() if system_freezing_cnt isn't zero * and tests whether @p needs to enter and stay in frozen state. Can be * called under any context. The freezers are responsible for ensuring the * target tasks see the updated state. */ bool freezing_slow_path(struct task_struct *p) { |
2b44c4db2 freezer: set PF_S... |
35 |
if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) |
a3201227f freezer: make fre... |
36 37 38 39 |
return false; if (pm_nosig_freezing || cgroup_freezing(p)) return true; |
34b087e48 freezer: kill unu... |
40 |
if (pm_freezing && !(p->flags & PF_KTHREAD)) |
a3201227f freezer: make fre... |
41 42 43 44 45 |
return true; return false; } EXPORT_SYMBOL(freezing_slow_path); |
8174f1503 container freezer... |
46 |
/* Refrigerator is place where frozen processes are stored :-). */ |
8a32c441c freezer: implemen... |
47 |
bool __refrigerator(bool check_kthr_stop) |
8174f1503 container freezer... |
48 49 50 |
{ /* Hmm, should we be allowed to suspend when there are realtime processes around? */ |
a0acae0e8 freezer: unexport... |
51 |
bool was_frozen = false; |
5ece3eae4 freezer: restruct... |
52 |
long save = current->state; |
8174f1503 container freezer... |
53 |
|
8174f1503 container freezer... |
54 55 |
pr_debug("%s entered refrigerator ", current->comm); |
8174f1503 container freezer... |
56 57 |
for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); |
5ece3eae4 freezer: restruct... |
58 59 60 |
spin_lock_irq(&freezer_lock); current->flags |= PF_FROZEN; |
6907483b4 freezer: make fre... |
61 |
if (!freezing(current) || |
8a32c441c freezer: implemen... |
62 |
(check_kthr_stop && kthread_should_stop())) |
5ece3eae4 freezer: restruct... |
63 64 65 66 |
current->flags &= ~PF_FROZEN; spin_unlock_irq(&freezer_lock); if (!(current->flags & PF_FROZEN)) |
8174f1503 container freezer... |
67 |
break; |
a0acae0e8 freezer: unexport... |
68 |
was_frozen = true; |
8174f1503 container freezer... |
69 70 |
schedule(); } |
6301cb95c sched: fix nr_uni... |
71 |
|
8174f1503 container freezer... |
72 73 |
pr_debug("%s left refrigerator ", current->comm); |
50fb4f7fc freezer: fix curr... |
74 75 76 77 78 79 80 |
/* * Restore saved task state before returning. The mb'd version * needs to be used; otherwise, it might silently break * synchronization which depends on ordered task state change. */ set_current_state(save); |
a0acae0e8 freezer: unexport... |
81 82 |
return was_frozen; |
8174f1503 container freezer... |
83 |
} |
a0acae0e8 freezer: unexport... |
84 |
EXPORT_SYMBOL(__refrigerator); |
8174f1503 container freezer... |
85 86 87 88 |
static void fake_signal_wake_up(struct task_struct *p) { unsigned long flags; |
37ad8aca9 freezer: use lock... |
89 90 91 92 |
if (lock_task_sighand(p, &flags)) { signal_wake_up(p, 0); unlock_task_sighand(p, &flags); } |
8174f1503 container freezer... |
93 94 95 |
} /** |
839e3407d freezer: remove u... |
96 97 |
* freeze_task - send a freeze request to given task * @p: task to send the request to |
8174f1503 container freezer... |
98 |
* |
37f08be11 PM / Freezer: Rem... |
99 100 101 |
* If @p is freezing, the freeze request is sent either by sending a fake * signal (if it's not a kernel thread) or waking it up (if it's a kernel * thread). |
839e3407d freezer: remove u... |
102 103 104 |
* * RETURNS: * %false, if @p is not freezing or already frozen; %true, otherwise |
8174f1503 container freezer... |
105 |
*/ |
839e3407d freezer: remove u... |
106 |
bool freeze_task(struct task_struct *p) |
8174f1503 container freezer... |
107 |
{ |
0c9af0926 freezer: use dedi... |
108 |
unsigned long flags; |
0c9af0926 freezer: use dedi... |
109 |
|
613f5d13b freezer: skip wak... |
110 111 112 113 114 115 116 117 118 119 120 |
/* * This check can race with freezer_do_not_count, but worst case that * will result in an extra wakeup being sent to the task. It does not * race with freezer_count(), the barriers in freezer_count() and * freezer_should_skip() ensure that either freezer_count() sees * freezing == true in try_to_freeze() and freezes, or * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task * normally. */ if (freezer_should_skip(p)) return false; |
0c9af0926 freezer: use dedi... |
121 |
spin_lock_irqsave(&freezer_lock, flags); |
a3201227f freezer: make fre... |
122 123 124 125 |
if (!freezing(p) || frozen(p)) { spin_unlock_irqrestore(&freezer_lock, flags); return false; } |
8174f1503 container freezer... |
126 |
|
5d8f72b55 freezer: change p... |
127 |
if (!(p->flags & PF_KTHREAD)) |
8cfe400ca Freezer: Fix a ra... |
128 |
fake_signal_wake_up(p); |
5d8f72b55 freezer: change p... |
129 |
else |
8174f1503 container freezer... |
130 |
wake_up_state(p, TASK_INTERRUPTIBLE); |
a3201227f freezer: make fre... |
131 |
|
0c9af0926 freezer: use dedi... |
132 |
spin_unlock_irqrestore(&freezer_lock, flags); |
a3201227f freezer: make fre... |
133 |
return true; |
8174f1503 container freezer... |
134 |
} |
a5be2d0d1 freezer: rename t... |
135 |
void __thaw_task(struct task_struct *p) |
dc52ddc0e container freezer... |
136 |
{ |
0c9af0926 freezer: use dedi... |
137 |
unsigned long flags; |
a5be2d0d1 freezer: rename t... |
138 |
|
6907483b4 freezer: make fre... |
139 140 141 142 143 144 |
/* * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to * be visible to @p as waking up implies wmb. Waking up inside * freezer_lock also prevents wakeups from leaking outside * refrigerator. */ |
0c9af0926 freezer: use dedi... |
145 |
spin_lock_irqsave(&freezer_lock, flags); |
34b087e48 freezer: kill unu... |
146 |
if (frozen(p)) |
a5be2d0d1 freezer: rename t... |
147 |
wake_up_process(p); |
0c9af0926 freezer: use dedi... |
148 |
spin_unlock_irqrestore(&freezer_lock, flags); |
dc52ddc0e container freezer... |
149 |
} |
96ee6d853 freezer: fix set_... |
150 151 |
/** |
34b087e48 freezer: kill unu... |
152 |
* set_freezable - make %current freezable |
96ee6d853 freezer: fix set_... |
153 154 155 |
* * Mark %current freezable and enter refrigerator if necessary. */ |
34b087e48 freezer: kill unu... |
156 |
bool set_freezable(void) |
96ee6d853 freezer: fix set_... |
157 158 159 160 161 162 163 164 165 166 |
{ might_sleep(); /* * Modify flags while holding freezer_lock. This ensures the * freezer notices that we aren't frozen yet or the freezing * condition is visible to try_to_freeze() below. */ spin_lock_irq(&freezer_lock); current->flags &= ~PF_NOFREEZE; |
96ee6d853 freezer: fix set_... |
167 168 169 170 |
spin_unlock_irq(&freezer_lock); return try_to_freeze(); } |
34b087e48 freezer: kill unu... |
171 |
EXPORT_SYMBOL(set_freezable); |