|
@@ -75,21 +75,79 @@ void refrigerator(void)
|
|
|
__set_current_state(save);
|
|
|
}
|
|
|
|
|
|
-static void freeze_task(struct task_struct *p)
|
|
|
+static void fake_signal_wake_up(struct task_struct *p, int resume)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
|
|
|
- if (!freezing(p)) {
|
|
|
+ spin_lock_irqsave(&p->sighand->siglock, flags);
|
|
|
+ signal_wake_up(p, resume);
|
|
|
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+static void send_fake_signal(struct task_struct *p)
|
|
|
+{
|
|
|
+ if (p->state == TASK_STOPPED)
|
|
|
+ force_sig_specific(SIGSTOP, p);
|
|
|
+ fake_signal_wake_up(p, p->state == TASK_STOPPED);
|
|
|
+}
|
|
|
+
|
|
|
+static int has_mm(struct task_struct *p)
|
|
|
+{
|
|
|
+ return (p->mm && !(p->flags & PF_BORROWED_MM));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * freeze_task - send a freeze request to given task
|
|
|
+ * @p: task to send the request to
|
|
|
+ * @with_mm_only: if set, the request will only be sent if the task has its
|
|
|
+ * own mm
|
|
|
+ * Return value: 0, if @with_mm_only is set and the task has no mm of its
|
|
|
+ * own or the task is frozen, 1, otherwise
|
|
|
+ *
|
|
|
+ * The freeze request is sent by seting the tasks's TIF_FREEZE flag and
|
|
|
+ * either sending a fake signal to it or waking it up, depending on whether
|
|
|
+ * or not it has its own mm (ie. it is a user land task). If @with_mm_only
|
|
|
+ * is set and the task has no mm of its own (ie. it is a kernel thread),
|
|
|
+ * its TIF_FREEZE flag should not be set.
|
|
|
+ *
|
|
|
+ * The task_lock() is necessary to prevent races with exit_mm() or
|
|
|
+ * use_mm()/unuse_mm() from occuring.
|
|
|
+ */
|
|
|
+static int freeze_task(struct task_struct *p, int with_mm_only)
|
|
|
+{
|
|
|
+ int ret = 1;
|
|
|
+
|
|
|
+ task_lock(p);
|
|
|
+ if (freezing(p)) {
|
|
|
+ if (has_mm(p)) {
|
|
|
+ if (!signal_pending(p))
|
|
|
+ fake_signal_wake_up(p, 0);
|
|
|
+ } else {
|
|
|
+ if (with_mm_only)
|
|
|
+ ret = 0;
|
|
|
+ else
|
|
|
+ wake_up_state(p, TASK_INTERRUPTIBLE);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
rmb();
|
|
|
- if (!frozen(p)) {
|
|
|
- set_freeze_flag(p);
|
|
|
- if (p->state == TASK_STOPPED)
|
|
|
- force_sig_specific(SIGSTOP, p);
|
|
|
- spin_lock_irqsave(&p->sighand->siglock, flags);
|
|
|
- signal_wake_up(p, p->state == TASK_STOPPED);
|
|
|
- spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
|
|
+ if (frozen(p)) {
|
|
|
+ ret = 0;
|
|
|
+ } else {
|
|
|
+ if (has_mm(p)) {
|
|
|
+ set_freeze_flag(p);
|
|
|
+ send_fake_signal(p);
|
|
|
+ } else {
|
|
|
+ if (with_mm_only) {
|
|
|
+ ret = 0;
|
|
|
+ } else {
|
|
|
+ set_freeze_flag(p);
|
|
|
+ wake_up_state(p, TASK_INTERRUPTIBLE);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ task_unlock(p);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static void cancel_freezing(struct task_struct *p)
|
|
@@ -119,31 +177,14 @@ static int try_to_freeze_tasks(int freeze_user_space)
|
|
|
if (frozen(p) || !freezeable(p))
|
|
|
continue;
|
|
|
|
|
|
- if (freeze_user_space) {
|
|
|
- if (p->state == TASK_TRACED &&
|
|
|
- frozen(p->parent)) {
|
|
|
- cancel_freezing(p);
|
|
|
- continue;
|
|
|
- }
|
|
|
- /*
|
|
|
- * Kernel threads should not have TIF_FREEZE set
|
|
|
- * at this point, so we must ensure that either
|
|
|
- * p->mm is not NULL *and* PF_BORROWED_MM is
|
|
|
- * unset, or TIF_FRREZE is left unset.
|
|
|
- * The task_lock() is necessary to prevent races
|
|
|
- * with exit_mm() or use_mm()/unuse_mm() from
|
|
|
- * occuring.
|
|
|
- */
|
|
|
- task_lock(p);
|
|
|
- if (!p->mm || (p->flags & PF_BORROWED_MM)) {
|
|
|
- task_unlock(p);
|
|
|
- continue;
|
|
|
- }
|
|
|
- freeze_task(p);
|
|
|
- task_unlock(p);
|
|
|
- } else {
|
|
|
- freeze_task(p);
|
|
|
+ if (p->state == TASK_TRACED && frozen(p->parent)) {
|
|
|
+ cancel_freezing(p);
|
|
|
+ continue;
|
|
|
}
|
|
|
+
|
|
|
+ if (!freeze_task(p, freeze_user_space))
|
|
|
+ continue;
|
|
|
+
|
|
|
if (!freezer_should_skip(p))
|
|
|
todo++;
|
|
|
} while_each_thread(g, p);
|