第四章 第四节 per_cpu
发布日期:2021-06-30 18:59:18 浏览次数:2 分类:技术文章

本文共 2608 字,大约阅读时间需要 8 分钟。

我们上一章说了

实现内核同步的方法很多,如下表

技术

说明

适用范围

每CPU变量

在CPU之间复制数据结构

所有CPU

原子操作

对一个计数器原子地“读-修改-写”的指令

所有CPU

内存屏障

避免指令重新排序

本地CPU或所有CPU

自旋锁

加锁时忙等

所有CPU

信号量

加锁时阻塞等待

所有CPU

顺序锁

基于访问计数器的锁

所有CPU

本地中断的禁止

禁止单个CPU上的中断处理

本地CPU

本地软中断的禁止

禁止单个CPU上的可延迟函数处理

本地CPU

读-复制-更新(RCU)

通过指针而不是锁来访问共享数据结构

所有CPU

但是这个每CPU变量,让我看起来非常的拗口,什么是每CPU变量,我刚开始看的时候,以为别人写错了,后面又查了很多资料,确定是对的,才放心,原来是翻译的问题

优点

per_cpu的好处是访问它不需要加锁,而且这个变量存在CPU的cache里,访问速度会非常快

原英文是 per_cpu

/*

* Add a offset to a pointer but keep the pointer as is.

*

* Only S390 provides its own means of moving the pointer.

*/

#ifndef SHIFT_PERCPU_PTR

/* Weird cast keeps both GCC and sparse happy. */

#define SHIFT_PERCPU_PTR(__p, __offset) ({ \

__verify_pcpu_ptr((__p)); \

RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \

})

#endif

/*

* A percpu variable may point to a discarded regions. The following are

* established ways to produce a usable pointer from the percpu variable

* offset.

*/

#define per_cpu(var, cpu) \

(*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))

既然这么拗口,我觉得就没有必要翻译了,直接说明是per_cpu 就好了

怎么使用这个 per_cpu 呢?

在源码

drivers\cpufreq\cpufreq_userspace.c

下面有一个使用的历程

声明一个 per_cpu

static DEFINE_PER_CPU(unsigned int, cpu_is_managed);

#define DEFINE_PER_CPU(type, name) \

DEFINE_PER_CPU_SECTION(type, name, "")

使用一个per_cpu

get_cpu_var(var) 和 set_cpu_var(var)

使用另一个CPU的per_cpu变量

per_cpu(cpu_cur_freq, freq->cpu) = freq->new;

导出一个per_cpu 变量供其他模块使用

EXPORT_PER_CPU_SYMBOL(per_cpu_var);

EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);

注意!!

在使用per_cpu的时候,记得禁止内核抢占

DECLARE_PER_CPU(int, mycounter);

● int cpu;

● preempt_disable(); //禁止抢占

● cpu = smp_processor_id();

● per_cpu(mycounter, cpu) += 1;

● preempt_enable(); //开启内核抢占

SMP系统chcae 命中

什么是smp 系统呢?就是有几个 CPU组成的芯片,就是我们通常说的几核几核的说法,大概的图像这样

           640?wx_fmt=png            

per_cpu解决的是多个CPU上共享数据的问题,如果声明了一个变量A,这个变量A在每个CPU下都有自己的副本,使用的堆栈地址也不一样,但是如果改变了A的值,其他的CPU同样能获取这个改变的值。

这样的话每个CPU只要关心单个CPU的并发问题,不用考虑多CPU的互斥加锁并发问题。

声明和定义Per-CPU变量的API

描述

DECLARE_PER_CPU(type, name) 

DEFINE_PER_CPU(type, name)

普通的、没有特殊要求的per cpu变量定义接口函数。没有对齐的要求

DECLARE_PER_CPU_FIRST(type, name) 

DEFINE_PER_CPU_FIRST(type, name)

通过该API定义的per cpu变量位于整个per cpu相关section的最前面。

DECLARE_PER_CPU_SHARED_ALIGNED(type, name) 

DEFINE_PER_CPU_SHARED_ALIGNED(type, name)

通过该API定义的per cpu变量在SMP的情况下会对齐到L1 cache line ,对于UP,不需要对齐到cachine line

DECLARE_PER_CPU_ALIGNED(type, name) 

DEFINE_PER_CPU_ALIGNED(type, name)

无论SMP或者UP,都是需要对齐到L1 cache line

DECLARE_PER_CPU_PAGE_ALIGNED(type, name) 

DEFINE_PER_CPU_PAGE_ALIGNED(type, name)

为定义page aligned per cpu变量而设定的API接口

DECLARE_PER_CPU_READ_MOSTLY(type, name) 

DEFINE_PER_CPU_READ_MOSTLY(type, name)

通过该API定义的per cpu变量是read mostly

per_cpu 在内存中固定的section

           640?wx_fmt=png            

参考资料:(公众号后台回复 per_cpu  获取)

           640?wx_fmt=png            

推荐阅读:


640?wx_fmt=jpeg

转载地址:https://linus.blog.csdn.net/article/details/99790871 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:安卓JNI传结构体
下一篇:第4章 第三节 内核同步

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月13日 00时09分59秒