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/module.h> 10 #include <linux/syscalls.h> 11 #include <linux/freezer.h> 12 13 /* 14 * freezing is complete, mark current process as frozen 15 */ 16 static inline void frozen_process(void) 17 { 18 if (!unlikely(current->flags & PF_NOFREEZE)) { 19 current->flags |= PF_FROZEN; 20 wmb(); 21 } 22 clear_freeze_flag(current); 23 } 24 25 /* Refrigerator is place where frozen processes are stored :-). */ 26 void refrigerator(void) 27 { 28 /* Hmm, should we be allowed to suspend when there are realtime 29 processes around? */ 30 long save; 31 32 task_lock(current); 33 if (freezing(current)) { 34 frozen_process(); 35 task_unlock(current); 36 } else { 37 task_unlock(current); 38 return; 39 } 40 save = current->state; 41 pr_debug("%s entered refrigerator\n", current->comm); 42 43 spin_lock_irq(¤t->sighand->siglock); 44 recalc_sigpending(); /* We sent fake signal, clean it up */ 45 spin_unlock_irq(¤t->sighand->siglock); 46 47 /* prevent accounting of that task to load */ 48 current->flags |= PF_FREEZING; 49 50 for (;;) { 51 set_current_state(TASK_UNINTERRUPTIBLE); 52 if (!frozen(current)) 53 break; 54 schedule(); 55 } 56 57 /* Remove the accounting blocker */ 58 current->flags &= ~PF_FREEZING; 59 60 pr_debug("%s left refrigerator\n", current->comm); 61 __set_current_state(save); 62 } 63 EXPORT_SYMBOL(refrigerator); 64 65 static void fake_signal_wake_up(struct task_struct *p) 66 { 67 unsigned long flags; 68 69 spin_lock_irqsave(&p->sighand->siglock, flags); 70 signal_wake_up(p, 0); 71 spin_unlock_irqrestore(&p->sighand->siglock, flags); 72 } 73 74 /** 75 * freeze_task - send a freeze request to given task 76 * @p: task to send the request to 77 * @sig_only: if set, the request will only be sent if the task has the 78 * PF_FREEZER_NOSIG flag unset 79 * Return value: 'false', if @sig_only is set and the task has 80 * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise 81 * 82 * The freeze request is sent by setting the tasks's TIF_FREEZE flag and 83 * either sending a fake signal to it or waking it up, depending on whether 84 * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task 85 * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its 86 * TIF_FREEZE flag will not be set. 87 */ 88 bool freeze_task(struct task_struct *p, bool sig_only) 89 { 90 /* 91 * We first check if the task is freezing and next if it has already 92 * been frozen to avoid the race with frozen_process() which first marks 93 * the task as frozen and next clears its TIF_FREEZE. 94 */ 95 if (!freezing(p)) { 96 rmb(); 97 if (frozen(p)) 98 return false; 99 100 if (!sig_only || should_send_signal(p)) 101 set_freeze_flag(p); 102 else 103 return false; 104 } 105 106 if (should_send_signal(p)) { 107 if (!signal_pending(p)) 108 fake_signal_wake_up(p); 109 } else if (sig_only) { 110 return false; 111 } else { 112 wake_up_state(p, TASK_INTERRUPTIBLE); 113 } 114 115 return true; 116 } 117 118 void cancel_freezing(struct task_struct *p) 119 { 120 unsigned long flags; 121 122 if (freezing(p)) { 123 pr_debug(" clean up: %s\n", p->comm); 124 clear_freeze_flag(p); 125 spin_lock_irqsave(&p->sighand->siglock, flags); 126 recalc_sigpending_and_wake(p); 127 spin_unlock_irqrestore(&p->sighand->siglock, flags); 128 } 129 } 130 131 static int __thaw_process(struct task_struct *p) 132 { 133 if (frozen(p)) { 134 p->flags &= ~PF_FROZEN; 135 return 1; 136 } 137 clear_freeze_flag(p); 138 return 0; 139 } 140 141 /* 142 * Wake up a frozen process 143 * 144 * task_lock() is needed to prevent the race with refrigerator() which may 145 * occur if the freezing of tasks fails. Namely, without the lock, if the 146 * freezing of tasks failed, thaw_tasks() might have run before a task in 147 * refrigerator() could call frozen_process(), in which case the task would be 148 * frozen and no one would thaw it. 149 */ 150 int thaw_process(struct task_struct *p) 151 { 152 task_lock(p); 153 if (__thaw_process(p) == 1) { 154 task_unlock(p); 155 wake_up_process(p); 156 return 1; 157 } 158 task_unlock(p); 159 return 0; 160 } 161 EXPORT_SYMBOL(thaw_process); 162