root/kernel/freezer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. freezing_slow_path
  2. __refrigerator
  3. fake_signal_wake_up
  4. freeze_task
  5. __thaw_task
  6. set_freezable

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

/* [<][>][^][v][top][bottom][index][help] */