• Linux 进程中 Stop, Park, Freeze【转】


    转自:https://blog.csdn.net/yiyeguzhou100/article/details/53134743

    http://kernel.meizu.com/linux-process-stop.html

    在调试内核的时候,经常会碰到几个相近的概念:进程 stop、进程 park、进程 freeze。这几个名词看起来都是停止进程,那么他们之间的区别和应用场景在分别是什么呢?下面就来分析一番。

    本文的代码分析基于 Linux kernel 3.18.22,最好的学习方法还是 “RTFSC”

    1. 进程 stop

    进程 stop 分成两种:用户进程 stop 和内核进程 stop。

    用户进程 stop 可以通过给进程发送 STOP 信号来实现,可以参考“Linux Signal”这一篇的描述。但是对内核进程来说不会响应信号,如果碰到需要 stop 内核进程的场景怎么处理?比如:我们在设备打开的时候创建了内核处理进程,在设备关闭的时候需要 stop 内核进程。

    Linux 实现了一套 kthread_stop() 的机制来实现内核进程 stop。

    1.1 内核进程的创建

    内核进程创建过程,是理解本篇的基础。

    可以看到 kthread_create() 并不是自己去创建内核进程,而是把创建任务推送给 kthreadd()进程执行。

    kthreadd() -> create_kthread() -> kernel_thread() 创建的新进程也不是直接使用用户的函数 threadfn(),而是创建通用函数 kthread()kthread() 再来调用 threadfn()

    • kernel/kthread.c:

    kthread_createkthread_create

    1.2 内核进程的 stop

    如果内核进程需要支持 kthread_stop(),需要根据以下框架来写代码。用户在主循环中调用 kthread_should_stop() 来判断当前 kthread 是否需要 stop,如果被 stop 则退出循环。

    这种代码为什么不做到通用代码 kthread() 中?这应该是和 Linux 的设计思想相关的。Linux 运行内核态的策略比较灵活,而对用户态的策略更加严格统一。

    kthread_should_stopkthread_should_stop

    kthread_should_stop() 和 kthread_stop() 的代码实现:

    • kernel/kthread.c:
    • kthread_should_stop()/kthread_stop()
    1.  
    2. bool kthread_should_stop(void)
    3. {
    4. // (1) 判断进程所在 kthread 结构中的 KTHREAD_SHOULD_STOP 是否被置位
    5. return test_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);
    6. }
    7.  
    8. int kthread_stop(struct task_struct *k)
    9. {
    10. struct kthread *kthread;
    11. int ret;
    12.  
    13. trace_sched_kthread_stop(k);
    14.  
    15. get_task_struct(k);
    16. kthread = to_live_kthread(k);
    17. if (kthread) {
    18. // (2) 置位进程所在 kthread 结构中的 KTHREAD_SHOULD_STOP
    19. set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
    20. // (3) unpark & wake_up 进程来响应 stop 信号
    21. __kthread_unpark(k, kthread);
    22. wake_up_process(k);
    23. wait_for_completion(&kthread->exited);
    24. }
    25. ret = k->exit_code;
    26. put_task_struct(k);
    27.  
    28. trace_sched_kthread_stop_ret(ret);
    29. return ret;
    30. }

    2. 进程 park

    smpboot_register_percpu_thread() 用来创建 per_cpu 内核进程,所谓的 per_cpu 进程是指需要在每个 online cpu 上创建线程。比如执行 stop_machine() 中 cpu 同步操作的 migration 进程:

    1. shell@:/ $ ps | grep migration
    2. root 10 2 0 0 smpboot_th 0000000000 S migration/0
    3. root 11 2 0 0 smpboot_th 0000000000 S migration/1
    4. root 15 2 0 0 __kthread_ 0000000000 R migration/2
    5. root 19 2 0 0 __kthread_ 0000000000 R migration/3
    6. root 207 2 0 0 __kthread_ 0000000000 R migration/8
    7. root 247 2 0 0 __kthread_ 0000000000 R migration/4
    8. root 251 2 0 0 __kthread_ 0000000000 R migration/5
    9. root 265 2 0 0 __kthread_ 0000000000 R migration/6
    10. root 356 2 0 0 __kthread_ 0000000000 R migration/7
    11. root 2165 2 0 0 __kthread_ 0000000000 R migration/9
    12.  

    问题来了,既然 per_cpu 进程是和 cpu 绑定的,那么在 cpu hotplug 的时候,进程需要相应的 disable 和 enable。实现的方法可以有多种:

    • 动态的销毁和创建线程。缺点是开销比较大。
    • 设置进程的 cpu 亲和力 set_cpus_allowed_ptr()。缺点是进程绑定的 cpu 如果被 down 掉,进程会迁移到其他 cpu 继续执行。

    为了克服上述方案的缺点,适配 per_cpu 进程的 cpu hotplug 操作,设计了 kthread_park()/kthread_unpark() 机制。

    2.1 smpboot_register_percpu_thread()

    per_cpu 进程从代码上看,实际也是调用 kthread_create() 来创建的。

    • kernel/smpboot.c:
    • kernel/kthread.c:

    smpboot_register_percpu_threadsmpboot_register_percpu_thread

    我们可以看到 smpboot_register 又增加了一层封装:kthread() -> smpboot_thread_fn() -> ht->thread_fn(),这种封装的使用可以参考 cpu_stop_threads。

    • kernel/stop_machine.c:
    1. static struct smp_hotplug_thread cpu_stop_threads = {
    2. .store = &cpu_stopper_task,
    3. .thread_should_run = cpu_stop_should_run,
    4. .thread_fn = cpu_stopper_thread,
    5. .thread_comm = "migration/%u",
    6. .create = cpu_stop_create,
    7. .setup = cpu_stop_unpark,
    8. .park = cpu_stop_park,
    9. .pre_unpark = cpu_stop_unpark,
    10. .selfparking = true,
    11. };
    12.  
    13. static int __init cpu_stop_init(void)
    14. {
    15. unsigned int cpu;
    16.  
    17. for_each_possible_cpu(cpu) {
    18. struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
    19.  
    20. spin_lock_init(&stopper->lock);
    21. INIT_LIST_HEAD(&stopper->works);
    22. }
    23.  
    24. BUG_ON(smpboot_register_percpu_thread(&cpu_stop_threads));
    25. stop_machine_initialized = true;
    26. return 0;
    27. }

    我们可以看到 smpboot_thread_fn() 循环中实现了对 park 的支持,具体实现 kthread_should_park()kthread_parkme()kthread_park()kthread_unpark() 的代码分析:

    • kernel/kthread.c:
    1. bool kthread_should_park(void)
    2. {
    3. // (1) 判断进程所在 kthread 结构中的 KTHREAD_SHOULD_PARK 是否被置位
    4. return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
    5. }
    6.  
    7. void kthread_parkme(void)
    8. {
    9. __kthread_parkme(to_kthread(current));
    10. }
    11. |
    12. static void __kthread_parkme(struct kthread *self)
    13. {
    14. // (2) 如果当前进程的 KTHREAD_SHOULD_PARK 标志被置位 ,
    15. // 将当前进程进入 TASK_PARKED 的阻塞状态。
    16. // 如果 KTHREAD_SHOULD_PARK 不清除,
    17. // 就算被 wake_up 唤醒还是会循环进入 TASK_PARKED 的阻塞状态。
    18. __set_current_state(TASK_PARKED);
    19. while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
    20. if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
    21. complete(&self->parked);
    22. schedule();
    23. __set_current_state(TASK_PARKED);
    24. }
    25. clear_bit(KTHREAD_IS_PARKED, &self->flags);
    26. __set_current_state(TASK_RUNNING);
    27. }
    28.  
    29. int kthread_park(struct task_struct *k)
    30. {
    31. struct kthread *kthread = to_live_kthread(k);
    32. int ret = -ENOSYS;
    33.  
    34. if (kthread) {
    35. // (3) 设置 KTHREAD_IS_PARKED 标志位,并且唤醒进程进入 park 状态
    36. if (!test_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
    37. set_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
    38. if (k != current) {
    39. wake_up_process(k);
    40. wait_for_completion(&kthread->parked);
    41. }
    42. }
    43. ret = 0;
    44. }
    45. return ret;
    46. }
    47.  
    48. void kthread_unpark(struct task_struct *k)
    49. {
    50. struct kthread *kthread = to_live_kthread(k);
    51.  
    52. if (kthread)
    53. __kthread_unpark(k, kthread);
    54. }
    55. |
    56. static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)
    57. {
    58. // (4) 清除 KTHREAD_IS_PARKED 标志位
    59. clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
    60. /*
    61. * We clear the IS_PARKED bit here as we don't wait
    62. * until the task has left the park code. So if we'd
    63. * park before that happens we'd see the IS_PARKED bit
    64. * which might be about to be cleared.
    65. */
    66. // 如果进程已经被 park,并且 wake_up 唤醒进程
    67. if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
    68. // 如果是 per_cpu 进程,重新绑定进程 cpu
    69. if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
    70. __kthread_bind(k, kthread->cpu, TASK_PARKED);
    71. wake_up_state(k, TASK_PARKED);
    72. }
    73. }
    74.  

    2.2 cpu hotplug 支持

    我们前面说到 park 机制的主要目的是为了 per_cpu 进程支持 cpu hotplug,具体怎么响应热插拔事件呢?

    • kernel/smpboot.c:

    park_hotplugpark_hotplug

    3. 进程 freeze

    在系统进入 suspend 的时候,会尝试冻住一些进程,以避免一些进程无关操作影响系统的 suspend 状态。主要的流程如下:

    • kernel/power/suspend.c:

    suspend_freeze_processessuspend_freeze_processes

    这 suspend_freeze 里面判断当前在那个阶段,有 3 个重要的变量:

    • system_freezing_cnt - >0 表示系统全局的 freeze 开始;
    • pm_freezing - =true 表示用户进程 freeze 开始;
    • pm_nosig_freezing - =true 表示内核进程 freeze 开始;

    具体代码分析如下:

    • kernel/power/process.c:
    • kernel/freezer.c:
    • suspend_freeze_processes() -> freeze_processes() -> try_to_freeze_tasks() -> freeze_task()
    1.  
    2. int freeze_processes(void)
    3. {
    4. int error;
    5. int oom_kills_saved;
    6.  
    7. error = __usermodehelper_disable(UMH_FREEZING);
    8. if (error)
    9. return error;
    10.  
    11. // (1) 置位 PF_SUSPEND_TASK,确保当前进程不会被 freeze
    12. /* Make sure this task doesn't get frozen */
    13. current->flags |= PF_SUSPEND_TASK;
    14.  
    15. // (2) 使用全局 freeze 标志 system_freezing_cnt
    16. if (!pm_freezing)
    17. atomic_inc(&system_freezing_cnt);
    18.  
    19. pm_wakeup_clear();
    20. printk("Freezing user space processes ... ");
    21. // (3) 使用用户进程 freeze 标志 pm_freezing
    22. pm_freezing = true;
    23. oom_kills_saved = oom_kills_count();
    24. // (4) freeze user_only 进程
    25. // 判断进程是否可以被 freeze,唤醒进程 freeze 自己
    26. error = try_to_freeze_tasks(true);
    27. if (!error) {
    28. __usermodehelper_set_disable_depth(UMH_DISABLED);
    29. oom_killer_disable();
    30.  
    31. /*
    32. * There might have been an OOM kill while we were
    33. * freezing tasks and the killed task might be still
    34. * on the way out so we have to double check for race.
    35. */
    36. if (oom_kills_count() != oom_kills_saved &&
    37. !check_frozen_processes()) {
    38. __usermodehelper_set_disable_depth(UMH_ENABLED);
    39. printk("OOM in progress.");
    40. error = -EBUSY;
    41. } else {
    42. printk("done.");
    43. }
    44. }
    45. printk(" ");
    46. BUG_ON(in_atomic());
    47.  
    48. if (error)
    49. thaw_processes();
    50. return error;
    51. }
    52. |
    53. static int try_to_freeze_tasks(bool user_only)
    54. {
    55. struct task_struct *g, *p;
    56. unsigned long end_time;
    57. unsigned int todo;
    58. bool wq_busy = false;
    59. struct timeval start, end;
    60. u64 elapsed_msecs64;
    61. unsigned int elapsed_msecs;
    62. bool wakeup = false;
    63. int sleep_usecs = USEC_PER_MSEC;
    64. #ifdef CONFIG_PM_SLEEP
    65. char suspend_abort[MAX_SUSPEND_ABORT_LEN];
    66. #endif
    67. do_gettimeofday(&start);
    68.  
    69. end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs);
    70.  
    71. // (4.1) 如果是 kernel freeze,
    72. // 停工有 WQ_FREEZABLE 标志的 workqueue
    73. // 将 wq 的 pwq->max_active 设置成 0,新的 work 不能被执行
    74. if (!user_only)
    75. freeze_workqueues_begin();
    76.  
    77. while (true) {
    78. todo = 0;
    79. read_lock(&tasklist_lock);
    80. // (4.2) 对每个进程执行 freeze_task()
    81. for_each_process_thread(g, p) {
    82. if (p == current || !freeze_task(p))
    83. continue;
    84.  
    85. if (!freezer_should_skip(p))
    86. todo++;
    87. }
    88. read_unlock(&tasklist_lock);
    89.  
    90. // (4.3) 如果是 kernel freeze,
    91. // 判断停工的 workqueue 中残留的 work 有没有执行完
    92. if (!user_only) {
    93. wq_busy = freeze_workqueues_busy();
    94. todo += wq_busy;
    95. }
    96.  
    97. if (!todo || time_after(jiffies, end_time))
    98. break;
    99.  
    100. if (pm_wakeup_pending()) {
    101. #ifdef CONFIG_PM_SLEEP
    102. pm_get_active_wakeup_sources(suspend_abort,
    103. MAX_SUSPEND_ABORT_LEN);
    104. log_suspend_abort_reason(suspend_abort);
    105. #endif
    106. wakeup = true;
    107. break;
    108. }
    109.  
    110. /*
    111. * We need to retry, but first give the freezing tasks some
    112. * time to enter the refrigerator. Start with an initial
    113. * 1 ms sleep followed by exponential backoff until 8 ms.
    114. */
    115. usleep_range(sleep_usecs / 2, sleep_usecs);
    116. if (sleep_usecs < 8 * USEC_PER_MSEC)
    117. sleep_usecs *= 2;
    118. }
    119.  
    120. do_gettimeofday(&end);
    121. elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
    122. do_div(elapsed_msecs64, NSEC_PER_MSEC);
    123. elapsed_msecs = elapsed_msecs64;
    124.  
    125. if (wakeup) {
    126. printk(" ");
    127. printk(KERN_ERR "Freezing of tasks aborted after %d.%03d seconds",
    128. elapsed_msecs / 1000, elapsed_msecs % 1000);
    129. } else if (todo) {
    130. printk(" ");
    131. printk(KERN_ERR "Freezing of tasks failed after %d.%03d seconds"
    132. " (%d tasks refusing to freeze, wq_busy=%d): ",
    133. elapsed_msecs / 1000, elapsed_msecs % 1000,
    134. todo - wq_busy, wq_busy);
    135.  
    136. read_lock(&tasklist_lock);
    137. for_each_process_thread(g, p) {
    138. if (p != current && !freezer_should_skip(p)
    139. && freezing(p) && !frozen(p))
    140. sched_show_task(p);
    141. }
    142. read_unlock(&tasklist_lock);
    143. } else {
    144. printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000,
    145. elapsed_msecs % 1000);
    146. }
    147.  
    148. return todo ? -EBUSY : 0;
    149. }
    150. ||
    151. bool freeze_task(struct task_struct *p)
    152. {
    153. unsigned long flags;
    154.  
    155. /*
    156. * This check can race with freezer_do_not_count, but worst case that
    157. * will result in an extra wakeup being sent to the task. It does not
    158. * race with freezer_count(), the barriers in freezer_count() and
    159. * freezer_should_skip() ensure that either freezer_count() sees
    160. * freezing == true in try_to_freeze() and freezes, or
    161. * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task
    162. * normally.
    163. */
    164. if (freezer_should_skip(p))
    165. return false;
    166.  
    167. spin_lock_irqsave(&freezer_lock, flags);
    168. // (4.2.1) 检查当前进程是否可以被 freeze,
    169. // 或者是否已经被 freeze
    170. if (!freezing(p) || frozen(p)) {
    171. spin_unlock_irqrestore(&freezer_lock, flags);
    172. return false;
    173. }
    174.  
    175. // (4.2.2) 如果是用户进程,伪造一个 signal 发送给进程
    176. if (!(p->flags & PF_KTHREAD))
    177. fake_signal_wake_up(p);
    178. // (4.2.3) 如果是内核进程,wake_up 内核进程
    179. else
    180. wake_up_state(p, TASK_INTERRUPTIBLE);
    181.  
    182. spin_unlock_irqrestore(&freezer_lock, flags);
    183. return true;
    184. }
    185. |||
    186. static inline bool freezing(struct task_struct *p)
    187. { 具体代码分析如下:
    188.  
    189. - kernel/power/process.c:
    190. - kernel/freezer.c:
    191. // 如果 system_freezing_cnt 为 0,说明全局 freeze 还没有开始
    192. if (likely(!atomic_read(&system_freezing_cnt)))
    193. return false;
    194. return freezing_slow_path(p);
    195. }
    196. ||||
    197. bool freezing_slow_path(struct task_struct *p)
    198. {
    199. // (PF_NOFREEZE | PF_SUSPEND_TASK) 当前进程不能被 freeze
    200. if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
    201. return false;
    202.  
    203. if (test_thread_flag(TIF_MEMDIE))
    204. return false;
    205.  
    206. // 如果 pm_nosig_freezing 为 true,内核进程 freeze 已经开始,
    207. // 当前进程可以被 freeze
    208. if (pm_nosig_freezing || cgroup_freezing(p))
    209. return true;
    210.  
    211. // 如果 pm_freezing 为 true,且当前进程为用户进程
    212. // 当前进程可以被 freeze
    213. if (pm_freezing && !(p->flags & PF_KTHREAD))
    214. return true;
    215.  
    216. return false;
    217. }

    3.1 用户进程 freeze

    freeze 用户态的进程利用了 signal 机制,系统 suspend 使能了 suspend 以后,调用 fake_signal_wake_up() 伪造一个信号唤醒进程,进程在 ret_to_user() -> do_notify_resume() -> do_signal() -> get_signal() -> try_to_freeze() 中 freeze 自己。

    具体代码分析如下:

    • kernel/freezer.c:
    1. static inline bool try_to_freeze(void)
    2. {
    3. if (!(current->flags & PF_NOFREEZE))
    4. debug_check_no_locks_held();
    5. return try_to_freeze_unsafe();
    6. }
    7. |
    8. static inline bool try_to_freeze_unsafe(void)
    9. {
    10. might_sleep();
    11. // 当前进程是否可以被 freeze
    12. if (likely(!freezing(current)))
    13. return false;
    14. // 调用 __refrigerator() freeze 当前进程
    15. return __refrigerator(false);
    16. }
    17. ||
    18. bool __refrigerator(bool check_kthr_stop)
    19. {
    20. /* Hmm, should we be allowed to suspend when there are realtime
    21. processes around? */
    22. bool was_frozen = false;
    23. long save = current->state;
    24.  
    25. pr_debug("%s entered refrigerator ", current->comm);
    26.  
    27. for (;;) {
    28. // (1) 设置当前进程进入 TASK_UNINTERRUPTIBLE 阻塞状态
    29. set_current_state(TASK_UNINTERRUPTIBLE);
    30.  
    31. spin_lock_irq(&freezer_lock);
    32. // (2) 设置已经 freeze 标志 PF_FROZEN
    33. current->flags |= PF_FROZEN;
    34. // (3) 如果当前进程已经不是 freeze 状态,
    35. // 退出 freeze
    36. if (!freezing(current) ||
    37. (check_kthr_stop && kthread_should_stop()))
    38. current->flags &= ~PF_FROZEN;
    39. spin_unlock_irq(&freezer_lock);
    40.  
    41. if (!(current->flags & PF_FROZEN))
    42. break;
    43. was_frozen = true;
    44. schedule();
    45. }
    46.  
    47. pr_debug("%s left refrigerator ", current->comm);
    48.  
    49. /*
    50. * Restore saved task state before returning. The mb'd version
    51. * needs to be used; otherwise, it might silently break
    52. * synchronization which depends on ordered task state change.
    53. */
    54. set_current_state(save);
    55.  
    56. return was_frozen;
    57. }

    3.2 内核进程 freeze

    内核进程对 freeze 的响应,有两个问题:

    • wake_up_state(p, TASK_INTERRUPTIBLE) 能唤醒哪些内核进程。
    • 内核进程怎么样来响应 freeze 状态,怎么样来 freeze 自己。

    如果进程阻塞在信号量、mutex 等内核同步机制上,wake_up_state 并不能解除阻塞。因为这些机制都有 while(1) 循环来判断条件,是否成立,不成立只是简单的唤醒随即又会进入阻塞睡眠状态。

    • kernel/locking/mutex.c:
    • mutex_lock() -> __mutex_lock_common()
    1. __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
    2. struct lockdep_map *nest_lock, unsigned long ip,
    3. struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)
    4. {
    5.  
    6. for (;;) {
    7. /*
    8. * Lets try to take the lock again - this is needed even if
    9. * we get here for the first time (shortly after failing to
    10. * acquire the lock), to make sure that we get a wakeup once
    11. * it's unlocked. Later on, if we sleep, this is the
    12. * operation that gives us the lock. We xchg it to -1, so
    13. * that when we release the lock, we properly wake up the
    14. * other waiters. We only attempt the xchg if the count is
    15. * non-negative in order to avoid unnecessary xchg operations:
    16. */
    17. // (1) 如果 mutex_lock 条件成立,才退出
    18. if (atomic_read(&lock->count) >= 0 &&
    19. (atomic_xchg(&lock->count, -1) == 1))
    20. break;
    21.  
    22. // (2) 如果如果有信号阻塞,也退出
    23. /*
    24. * got a signal? (This code gets eliminated in the
    25. * TASK_UNINTERRUPTIBLE case.)
    26. */
    27. if (unlikely(signal_pending_state(state, task))) {
    28. ret = -EINTR;
    29. goto err;
    30. }
    31.  
    32. if (use_ww_ctx && ww_ctx->acquired > 0) {
    33. ret = __mutex_lock_check_stamp(lock, ww_ctx);
    34. if (ret)
    35. goto err;
    36. }
    37.  
    38. // (3) 否则继续进入阻塞休眠状态
    39. __set_task_state(task, state);
    40.  
    41. /* didn't get the lock, go to sleep: */
    42. spin_unlock_mutex(&lock->wait_lock, flags);
    43. schedule_preempt_disabled();
    44. spin_lock_mutex(&lock->wait_lock, flags);
    45. }
    46.  
    47. }

    所以 wake_up_state() 只能唤醒这种简单阻塞的内核进程,而对于阻塞在内核同步机制上是无能无力的:

    1. void user_thread()
    2. {
    3. while(1)
    4. {
    5. set_current_state(TASK_UNINTERRUPTIBLE);
    6. schedule();
    7.  
    8. }
    9. }

    内核进程响应 freeze 操作,也必须显式的调用 try_to_freeze() 或者 kthread_freezable_should_stop() 来 freeze 自己:

    1. void user_thread()
    2. {
    3. while (!kthread_should_stop()) {
    4.  
    5. try_to_freeze();
    6.  
    7. }
    8. }

    所以从代码逻辑上看内核进程 freeze,并不会 freeze 所有内核进程,只 freeze 了 2 部分:一部分是设置了 WQ_FREEZABLE 标志的 workqueue,另一部分是内核进程主动调用 try_to_freeze() 并且在架构上设计的可以响应 freeze。



    附:

    static int
    kthread(void *vp)
    {
    struct ktstate *k;
    DECLARE_WAITQUEUE(wait, current);
    int more;
    k = vp;
    current->flags |= PF_NOFREEZE;
    set_user_nice(current, -10); //内核线程默认优先级
    complete(&k->rendez);/* tell spawner we're running */
    do {
    spin_lock_irq(k->lock);
    more = k->fn();
    if (!more) {
    add_wait_queue(k->waitq, &wait);
    __set_current_state(TASK_INTERRUPTIBLE);
    }
    spin_unlock_irq(k->lock);
    if (!more) {
    schedule();
    remove_wait_queue(k->waitq, &wait);
    } else
    cond_resched();
    } while (!kthread_should_stop());
    complete(&k->rendez);/* tell spawner we're stopping */
    return 0;
    }

  • 相关阅读:
    java练习题2
    java练习题
    java输入输出
    字符集
    eclipse快捷键
    类和对象练习-people
    类和对象-三角形
    权限修饰符-输出求和阶乘
    权限修饰符-练习
    权限修饰符-father&&son
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/9340497.html
Copyright © 2020-2023  润新知