Blame view
kernel/freezer.c
4.44 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; |
85fbd722a
|
21 22 23 24 25 |
/* * Temporary export for the deadlock workaround in ata_scsi_hotplug(). * Remove once the hack becomes unnecessary. */ EXPORT_SYMBOL_GPL(pm_freezing); |
0c9af0926
|
26 27 |
/* protects freezing and frozen transitions */ static DEFINE_SPINLOCK(freezer_lock); |
8174f1503
|
28 |
|
a3201227f
|
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) { |
2b44c4db2
|
40 |
if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) |
a3201227f
|
41 |
return false; |
51fae6da6
|
42 43 |
if (test_thread_flag(TIF_MEMDIE)) return false; |
a3201227f
|
44 45 |
if (pm_nosig_freezing || cgroup_freezing(p)) return true; |
34b087e48
|
46 |
if (pm_freezing && !(p->flags & PF_KTHREAD)) |
a3201227f
|
47 48 49 50 51 |
return true; return false; } EXPORT_SYMBOL(freezing_slow_path); |
8174f1503
|
52 |
/* Refrigerator is place where frozen processes are stored :-). */ |
8a32c441c
|
53 |
bool __refrigerator(bool check_kthr_stop) |
8174f1503
|
54 55 56 |
{ /* Hmm, should we be allowed to suspend when there are realtime processes around? */ |
a0acae0e8
|
57 |
bool was_frozen = false; |
5ece3eae4
|
58 |
long save = current->state; |
8174f1503
|
59 |
|
8174f1503
|
60 61 |
pr_debug("%s entered refrigerator ", current->comm); |
8174f1503
|
62 63 |
for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); |
5ece3eae4
|
64 65 66 |
spin_lock_irq(&freezer_lock); current->flags |= PF_FROZEN; |
6907483b4
|
67 |
if (!freezing(current) || |
8a32c441c
|
68 |
(check_kthr_stop && kthread_should_stop())) |
5ece3eae4
|
69 70 71 72 |
current->flags &= ~PF_FROZEN; spin_unlock_irq(&freezer_lock); if (!(current->flags & PF_FROZEN)) |
8174f1503
|
73 |
break; |
a0acae0e8
|
74 |
was_frozen = true; |
8174f1503
|
75 76 |
schedule(); } |
6301cb95c
|
77 |
|
8174f1503
|
78 79 |
pr_debug("%s left refrigerator ", current->comm); |
50fb4f7fc
|
80 81 82 83 84 85 86 |
/* * 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
|
87 88 |
return was_frozen; |
8174f1503
|
89 |
} |
a0acae0e8
|
90 |
EXPORT_SYMBOL(__refrigerator); |
8174f1503
|
91 92 93 94 |
static void fake_signal_wake_up(struct task_struct *p) { unsigned long flags; |
37ad8aca9
|
95 96 97 98 |
if (lock_task_sighand(p, &flags)) { signal_wake_up(p, 0); unlock_task_sighand(p, &flags); } |
8174f1503
|
99 100 101 |
} /** |
839e3407d
|
102 103 |
* freeze_task - send a freeze request to given task * @p: task to send the request to |
8174f1503
|
104 |
* |
37f08be11
|
105 106 107 |
* 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
|
108 109 110 |
* * RETURNS: * %false, if @p is not freezing or already frozen; %true, otherwise |
8174f1503
|
111 |
*/ |
839e3407d
|
112 |
bool freeze_task(struct task_struct *p) |
8174f1503
|
113 |
{ |
0c9af0926
|
114 |
unsigned long flags; |
0c9af0926
|
115 |
|
613f5d13b
|
116 117 118 119 120 121 122 123 124 125 126 |
/* * 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
|
127 |
spin_lock_irqsave(&freezer_lock, flags); |
a3201227f
|
128 129 130 131 |
if (!freezing(p) || frozen(p)) { spin_unlock_irqrestore(&freezer_lock, flags); return false; } |
8174f1503
|
132 |
|
5d8f72b55
|
133 |
if (!(p->flags & PF_KTHREAD)) |
8cfe400ca
|
134 |
fake_signal_wake_up(p); |
5d8f72b55
|
135 |
else |
8174f1503
|
136 |
wake_up_state(p, TASK_INTERRUPTIBLE); |
a3201227f
|
137 |
|
0c9af0926
|
138 |
spin_unlock_irqrestore(&freezer_lock, flags); |
a3201227f
|
139 |
return true; |
8174f1503
|
140 |
} |
a5be2d0d1
|
141 |
void __thaw_task(struct task_struct *p) |
dc52ddc0e
|
142 |
{ |
0c9af0926
|
143 |
unsigned long flags; |
a5be2d0d1
|
144 |
|
0c9af0926
|
145 |
spin_lock_irqsave(&freezer_lock, flags); |
34b087e48
|
146 |
if (frozen(p)) |
a5be2d0d1
|
147 |
wake_up_process(p); |
0c9af0926
|
148 |
spin_unlock_irqrestore(&freezer_lock, flags); |
dc52ddc0e
|
149 |
} |
96ee6d853
|
150 151 |
/** |
34b087e48
|
152 |
* set_freezable - make %current freezable |
96ee6d853
|
153 154 155 |
* * Mark %current freezable and enter refrigerator if necessary. */ |
34b087e48
|
156 |
bool set_freezable(void) |
96ee6d853
|
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
|
167 168 169 170 |
spin_unlock_irq(&freezer_lock); return try_to_freeze(); } |
34b087e48
|
171 |
EXPORT_SYMBOL(set_freezable); |