freezer.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * kernel/freezer.c - Function to freeze a process
  3. *
  4. * Originally from kernel/power/process.c
  5. */
  6. #include <linux/interrupt.h>
  7. #include <linux/suspend.h>
  8. #include <linux/export.h>
  9. #include <linux/syscalls.h>
  10. #include <linux/freezer.h>
  11. #include <linux/kthread.h>
  12. /* protects freezing and frozen transitions */
  13. static DEFINE_SPINLOCK(freezer_lock);
  14. /* Refrigerator is place where frozen processes are stored :-). */
  15. bool __refrigerator(bool check_kthr_stop)
  16. {
  17. /* Hmm, should we be allowed to suspend when there are realtime
  18. processes around? */
  19. bool was_frozen = false;
  20. long save;
  21. /*
  22. * Enter FROZEN. If NOFREEZE, schedule immediate thawing by
  23. * clearing freezing.
  24. */
  25. spin_lock_irq(&freezer_lock);
  26. repeat:
  27. if (!freezing(current)) {
  28. spin_unlock_irq(&freezer_lock);
  29. return was_frozen;
  30. }
  31. if (current->flags & PF_NOFREEZE)
  32. clear_freeze_flag(current);
  33. current->flags |= PF_FROZEN;
  34. spin_unlock_irq(&freezer_lock);
  35. save = current->state;
  36. pr_debug("%s entered refrigerator\n", current->comm);
  37. spin_lock_irq(&current->sighand->siglock);
  38. recalc_sigpending(); /* We sent fake signal, clean it up */
  39. spin_unlock_irq(&current->sighand->siglock);
  40. /* prevent accounting of that task to load */
  41. current->flags |= PF_FREEZING;
  42. for (;;) {
  43. set_current_state(TASK_UNINTERRUPTIBLE);
  44. if (!freezing(current) ||
  45. (check_kthr_stop && kthread_should_stop()))
  46. break;
  47. was_frozen = true;
  48. schedule();
  49. }
  50. /* Remove the accounting blocker */
  51. current->flags &= ~PF_FREEZING;
  52. /* leave FROZEN */
  53. spin_lock_irq(&freezer_lock);
  54. if (freezing(current))
  55. goto repeat;
  56. current->flags &= ~PF_FROZEN;
  57. spin_unlock_irq(&freezer_lock);
  58. pr_debug("%s left refrigerator\n", current->comm);
  59. /*
  60. * Restore saved task state before returning. The mb'd version
  61. * needs to be used; otherwise, it might silently break
  62. * synchronization which depends on ordered task state change.
  63. */
  64. set_current_state(save);
  65. return was_frozen;
  66. }
  67. EXPORT_SYMBOL(__refrigerator);
  68. static void fake_signal_wake_up(struct task_struct *p)
  69. {
  70. unsigned long flags;
  71. spin_lock_irqsave(&p->sighand->siglock, flags);
  72. signal_wake_up(p, 0);
  73. spin_unlock_irqrestore(&p->sighand->siglock, flags);
  74. }
  75. /**
  76. * freeze_task - send a freeze request to given task
  77. * @p: task to send the request to
  78. * @sig_only: if set, the request will only be sent if the task has the
  79. * PF_FREEZER_NOSIG flag unset
  80. * Return value: 'false', if @sig_only is set and the task has
  81. * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
  82. *
  83. * The freeze request is sent by setting the tasks's TIF_FREEZE flag and
  84. * either sending a fake signal to it or waking it up, depending on whether
  85. * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
  86. * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
  87. * TIF_FREEZE flag will not be set.
  88. */
  89. bool freeze_task(struct task_struct *p, bool sig_only)
  90. {
  91. unsigned long flags;
  92. bool ret = false;
  93. spin_lock_irqsave(&freezer_lock, flags);
  94. if (sig_only && !should_send_signal(p))
  95. goto out_unlock;
  96. if (frozen(p))
  97. goto out_unlock;
  98. set_freeze_flag(p);
  99. if (should_send_signal(p)) {
  100. fake_signal_wake_up(p);
  101. /*
  102. * fake_signal_wake_up() goes through p's scheduler
  103. * lock and guarantees that TASK_STOPPED/TRACED ->
  104. * TASK_RUNNING transition can't race with task state
  105. * testing in try_to_freeze_tasks().
  106. */
  107. } else {
  108. wake_up_state(p, TASK_INTERRUPTIBLE);
  109. }
  110. ret = true;
  111. out_unlock:
  112. spin_unlock_irqrestore(&freezer_lock, flags);
  113. return ret;
  114. }
  115. void cancel_freezing(struct task_struct *p)
  116. {
  117. unsigned long flags;
  118. spin_lock_irqsave(&freezer_lock, flags);
  119. if (freezing(p)) {
  120. pr_debug(" clean up: %s\n", p->comm);
  121. clear_freeze_flag(p);
  122. spin_lock(&p->sighand->siglock);
  123. recalc_sigpending_and_wake(p);
  124. spin_unlock(&p->sighand->siglock);
  125. }
  126. spin_unlock_irqrestore(&freezer_lock, flags);
  127. }
  128. void __thaw_task(struct task_struct *p)
  129. {
  130. unsigned long flags;
  131. /*
  132. * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to
  133. * be visible to @p as waking up implies wmb. Waking up inside
  134. * freezer_lock also prevents wakeups from leaking outside
  135. * refrigerator.
  136. */
  137. spin_lock_irqsave(&freezer_lock, flags);
  138. clear_freeze_flag(p);
  139. if (frozen(p))
  140. wake_up_process(p);
  141. spin_unlock_irqrestore(&freezer_lock, flags);
  142. }