为什么 preempt_count 每个线程就足够了

Why it is sufficient for preempt_count to be per thread

preempt_count 变量跟踪每个 CPU 统计数据::

 static __always_inline int preempt_count(void)
    {
            return current_thread_info()->preempt_count;
    }

位 0 - 7 跟踪内核抢占被禁用的次数。

第 8 - 15 位如果非零,表示软中断被禁用该次数。

位 16 - 27 指定了 irq_enter 的调用次数。它表示嵌套中断处理程序的数量。

我无法理解为什么 preempt_count 每个线程。 当一个新进程被调度时,off course bit 0-7 将为零,否则意味着抢占被禁用并且不允许切换。但是第 8 - 27 位呢?它们也会是 0 吗? 这是否意味着每当有进程调度调用时,那时 preempt_count 应该为 0,因此不需要在不同进程的 thread_info 之间复制它的值来跟踪状态 softirqs和特定 CPU?

上的 irq

Linux 禁止线程在中断时被调度,这是一个约定,没有代码来实现这个 restraint.So 在这个约定下新线程的 preempt_count 必须为零并且不需要复制 preempt_count.If 有人在中断上下文中调用调度可能还有其他问题,例如无法处理新中断,因为先前的中断已禁用中断。

current_thread_info 依赖于体系结构。它指向内核堆栈的末尾。 2.6 之前在内核堆栈的末尾 task_struct 离开。但是在 task_struct 移动到 slab 并且 thread_info 替换了 task_struct 之后。每个进程都有 thread_info 位于该任务的内核堆栈末尾。 current_thread_info() return arch 依赖指针(根据堆栈指针和大小计算)。 Thread_info有preempt_count是计数器。如果值为零,则内核可以被抢占(preempt_count += SOFTIRQ_OFFSET - 禁用下半部分)。 preempt_count 锁被持有时递增,锁被释放时递减。如果 irq 句柄完成并且指令指针应该指向内核代码。内核应该检查 preempt_count 是否为零,以便代码抢占是安全的,同时检查是否设置了来自相同 thread_info 的 need_reshed。调度程序应该开始更重要的任务。如果 preempt_count 非零 - 抢占不安全,下一次执行应指向与中断相同的任务。只有当当前任务释放所有锁并且 preempt_count == 0 时,代码才能安全抢占。再次 need_recshed 检查。

另一方面,preempt_count() 函数对于 preempt_disable()、preempt_enable() 两个嵌套函数非常有帮助。抢占功能可以保护每个 cpu 变量免受使用相同 per_cpu 变量的多个任务的并发访问。重要的是只有一个任务应该使用共享 per_cpu 变量(在 meedle 中它可以被其他任务更改)并且应该禁用抢占。 Preamption 函数是嵌套的,因此我们可以使用 preempt_count()。 in_atomic 基于 preempt_count() 实际上它解释了为什么它不是很好的功能。