cpu_relax()函数的意义

版权声明:转载请说明,谢谢。 https://blog.csdn.net/wuming_422103632/article/details/82388970

最近在看wake_up_process流程的时候,发现在try_to_wake_up函数里面有这么一条语句:

    while (p->on_cpu)
        cpu_relax();

一直想弄明白cpu_relax()函数的真实含义.
我们查看这个函数的定义如下:
ARM32:

#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
#define cpu_relax()         smp_mb()
#else
#define cpu_relax()         barrier()
#endif

ARM64:

static inline void cpu_relax(void)
{
    asm volatile("yield" ::: "memory");
}

能够看到:

  • ARM32中,在调用cpu_relax()函数的时候,只有内存屏障
  • ARM64中,在调用cpu_relax()函数的时候,不仅仅有内存屏障还存一个yield指令,是让cpu松弛下来,降低功耗,把资源配置给其他thread等.

详细的解释如下:
我们知道cpu_relax()是用于busy loop的场景.比如下面的代码:

    while (p->on_cpu)
        cpu_relax();

p->on_cpu的数值是期待其他进程修改的,从而解除本cpu的忙等待状态.
cpu_relax必须具备两个功能:

1、确保对p->on_cpu的访问每次都从memory中加载,也就是barrier()函数的作用;
2、通知底层CPU,ARM32的代码没有在做什么实际有意义的事情,如果可以的话,别让cpu做太多事情,系统的资源尽量让给其他的cpu。ARM64目前支持

当然,由于ARMv8之前的CPU不支持上面的第二个功能,所以只会看到的cpu_relax()就是barrier()。我们看到ARM64的代码

static inline void cpu_relax(void)
{
    asm volatile("yield" ::: "memory");
}

在这里, 嵌入式汇编中的clobber list没有描述汇编代码对寄存器的修改情况,只是有一个memory的标记。我们知道,clober list是gcc和gas的接口,用于gas通知gcc它对寄存器和memory的修改情况。因此,这里的memory就是告知gcc,在汇编代码中,我修改了memory中的内容,cpu_relax()之前的c代码块和cpu_relax()之后的c代码块看到的memory是不一样的,对memory的访问不能依赖于嵌入式汇编之前的c代码块中寄存器的内容,需要重新加载,这也就是Optimization barrier的功能。而 嵌入式汇编中的yield指令则完成了cpu_relax的第二个功能,即让CPU 松弛下来,降低功耗,把资源配置给其他thread等。

猜你喜欢

转载自blog.csdn.net/wuming_422103632/article/details/82388970