Blame view
kernel/freezer.c
4.19 KB
8174f1503
|
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
|
9 |
#include <linux/export.h> |
8174f1503
|
10 11 |
#include <linux/syscalls.h> #include <linux/freezer.h> |
8a32c441c
|
12 |
#include <linux/kthread.h> |
8174f1503
|
13 |
|
a3201227f
|
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
|
21 22 |
/* protects freezing and frozen transitions */ static DEFINE_SPINLOCK(freezer_lock); |
8174f1503
|
23 |
|
a3201227f
|
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/** * 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) { if (p->flags & PF_NOFREEZE) return false; if (pm_nosig_freezing || cgroup_freezing(p)) return true; |
34b087e48
|
40 |
if (pm_freezing && !(p->flags & PF_KTHREAD)) |
a3201227f
|
41 42 43 44 45 |
return true; return false; } EXPORT_SYMBOL(freezing_slow_path); |
8174f1503
|
46 |
/* Refrigerator is place where frozen processes are stored :-). */ |
8a32c441c
|
47 |
bool __refrigerator(bool check_kthr_stop) |
8174f1503
|
48 49 50 |
{ /* Hmm, should we be allowed to suspend when there are realtime processes around? */ |
a0acae0e8
|
51 |
bool was_frozen = false; |
5ece3eae4
|
52 |
long save = current->state; |
8174f1503
|
53 |
|
8174f1503
|
54 55 |
pr_debug("%s entered refrigerator ", current->comm); |
8174f1503
|
56 57 |
for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); |
5ece3eae4
|
58 59 60 |
spin_lock_irq(&freezer_lock); current->flags |= PF_FROZEN; |
6907483b4
|
61 |
if (!freezing(current) || |
8a32c441c
|
62 |
(check_kthr_stop && kthread_should_stop())) |
5ece3eae4
|
63 64 65 66 |
current->flags &= ~PF_FROZEN; spin_unlock_irq(&freezer_lock); if (!(current->flags & PF_FROZEN)) |
8174f1503
|
67 |
break; |
a0acae0e8
|
68 |
was_frozen = true; |
8174f1503
|
69 70 |
schedule(); } |
6301cb95c
|
71 |
|
8174f1503
|
72 73 |
pr_debug("%s left refrigerator ", current->comm); |
50fb4f7fc
|
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
|
81 82 |
return was_frozen; |
8174f1503
|
83 |
} |
a0acae0e8
|
84 |
EXPORT_SYMBOL(__refrigerator); |
8174f1503
|
85 86 87 88 |
static void fake_signal_wake_up(struct task_struct *p) { unsigned long flags; |
37ad8aca9
|
89 90 91 92 |
if (lock_task_sighand(p, &flags)) { signal_wake_up(p, 0); unlock_task_sighand(p, &flags); } |
8174f1503
|
93 94 95 |
} /** |
839e3407d
|
96 97 |
* freeze_task - send a freeze request to given task * @p: task to send the request to |
8174f1503
|
98 |
* |
37f08be11
|
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
|
102 103 104 |
* * RETURNS: * %false, if @p is not freezing or already frozen; %true, otherwise |
8174f1503
|
105 |
*/ |
839e3407d
|
106 |
bool freeze_task(struct task_struct *p) |
8174f1503
|
107 |
{ |
0c9af0926
|
108 |
unsigned long flags; |
0c9af0926
|
109 110 |
spin_lock_irqsave(&freezer_lock, flags); |
a3201227f
|
111 112 113 114 |
if (!freezing(p) || frozen(p)) { spin_unlock_irqrestore(&freezer_lock, flags); return false; } |
8174f1503
|
115 |
|
34b087e48
|
116 |
if (!(p->flags & PF_KTHREAD)) { |
8cfe400ca
|
117 118 119 120 121 122 123 |
fake_signal_wake_up(p); /* * fake_signal_wake_up() goes through p's scheduler * lock and guarantees that TASK_STOPPED/TRACED -> * TASK_RUNNING transition can't race with task state * testing in try_to_freeze_tasks(). */ |
8174f1503
|
124 125 126 |
} else { wake_up_state(p, TASK_INTERRUPTIBLE); } |
a3201227f
|
127 |
|
0c9af0926
|
128 |
spin_unlock_irqrestore(&freezer_lock, flags); |
a3201227f
|
129 |
return true; |
8174f1503
|
130 |
} |
a5be2d0d1
|
131 |
void __thaw_task(struct task_struct *p) |
dc52ddc0e
|
132 |
{ |
0c9af0926
|
133 |
unsigned long flags; |
a5be2d0d1
|
134 |
|
6907483b4
|
135 136 137 138 139 140 |
/* * 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
|
141 |
spin_lock_irqsave(&freezer_lock, flags); |
34b087e48
|
142 |
if (frozen(p)) |
a5be2d0d1
|
143 |
wake_up_process(p); |
0c9af0926
|
144 |
spin_unlock_irqrestore(&freezer_lock, flags); |
dc52ddc0e
|
145 |
} |
96ee6d853
|
146 147 |
/** |
34b087e48
|
148 |
* set_freezable - make %current freezable |
96ee6d853
|
149 150 151 |
* * Mark %current freezable and enter refrigerator if necessary. */ |
34b087e48
|
152 |
bool set_freezable(void) |
96ee6d853
|
153 154 155 156 157 158 159 160 161 162 |
{ 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
|
163 164 165 166 |
spin_unlock_irq(&freezer_lock); return try_to_freeze(); } |
34b087e48
|
167 |
EXPORT_SYMBOL(set_freezable); |