Linux内核机制开发 - DEFINE_PER_CPU和DECLARE_PER_CPU

By: fulinux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎点赞和订阅!
你的喜欢就是我写作的动力!

在这里插入图片描述

参考:Linux内核机制—percpu

1. DEFINE_PER_CPU和DECLARE_PER_CPU

DEFINE_PER_CPU 和 DECLARE_PER_CPU 是 Linux 内核中用于声明和定义 per-CPU 变量的宏。这些宏允许内核在每个 CPU 上拥有独立的变量副本,这对于多处理器系统上的并发编程非常有用,可以避免锁的竞争。

1. 1. DEFINE_PER_CPU

DEFINE_PER_CPU 宏用于定义一个 per-CPU 变量。它通常在内核模块的源代码文件中使用,直接定义一个全局变量。使用DEFINE_PER_CPU 宏定义的变量会被放置在特定的内存区域,每个 CPU 都有自己的副本。
语法:

DEFINE_PER_CPU(type, name);
  • type: 变量的数据类型。
  • name: 变量的名称。

1.2. DECLARE_PER_CPU

DECLARE_PER_CPU 宏用于声明一个 per-CPU 变量。它通常在头文件中使用,用来声明一个 per-CPU 变量,而实际的定义则需要在某个源文件中通过 DEFINE_PER_CPU 来完成。

DECLARE_PER_CPU(type, name);
  • type: 变量的数据类型。
  • name: 变量的名称。

2. 区别

2.1. 定义与声明:

  • DEFINE_PER_CPU 既定义了变量,也声明了它。这意味着你可以在源文件中直接使用 DEFINE_PER_CPU 来创建一个 per-CPU 变量。
  • DECLARE_PER_CPU 只声明变量,实际的定义需要在其他地方使用 DEFINE_PER_CPU 来完成。

2.2. 使用场景:

  • DEFINE_PER_CPU 通常用于源文件中,直接定义 per-CPU 变量。
  • DECLARE_PER_CPU 通常用于头文件中,提供外部接口访问 per-CPU 变量。

2.3. 编译器处理:

  • DEFINE_PER_CPU 会直接在源文件中创建变量的定义。
  • DECLARE_PER_CPU 则只在头文件中声明变量的存在,不会创建实际的变量定义。

3. 使用方法

假设我们有一个 per-CPU 变量 my_counter,我们可以这样声明和定义它:

//per_cpu.h
#ifndef PER_CPU_H
#define PER_CPU_H

DECLARE_PER_CPU(int, my_counter);

#endif /* PER_CPU_H */
//源文件per_cpu.c
#include "per_cpu.h"

DEFINE_PER_CPU(int, my_counter);

一旦 my_counter 被声明和定义,你就可以在内核模块或其他源文件中使用它。可以通过 __get_cpu_var 或 __this_cpu_read 宏来读取当前 CPU 的副本,通过 __set_cpu_var 或 __this_cpu_write 来修改当前 CPU 的副本。
读取 my_counter

int current_cpu_counter = __this_cpu_read(my_counter);

或者

int cpu_id = smp_processor_id();
int counter_value = __get_cpu_var(my_counter)[cpu_id];

修改 my_counter

__this_cpu_write(my_counter, value);

或者:

int cpu_id = smp_processor_id();
__set_cpu_var(my_counter)[cpu_id] = value;

4.示例使用 my_counter

假设你想要在一个内核模块中初始化 my_counter 并在每个 CPU 上递增它。
内核模块 (my_module.c)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include "per_cpu.h"

static int __init my_module_init(void)
{
    int cpu;

    for_each_online_cpu(cpu) {
        __set_cpu_var(my_counter)[cpu] = 0;  // 初始化每个 CPU 的 my_counter
    }

    printk(KERN_INFO "Module initialized.\n");
    return 0;
}

static void __exit my_module_exit(void)
{
    printk(KERN_INFO "Module removed.\n");
}

module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

增加计数器的函数 (increment_counter.c)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include "per_cpu.h"

void increment_my_counter(void)
{
    int cpu_id = smp_processor_id();
    int current_value = __get_cpu_var(my_counter)[cpu_id];
    __set_cpu_var(my_counter)[cpu_id] = current_value + 1;
}

5. 总结

  1. 使用 __this_cpu_read 和 __this_cpu_write 来读取和修改当前 CPU 的副本。
  2. 使用 __get_cpu_var 和 __set_cpu_var 来访问特定 CPU 的副本。
    这样,你就可以在内核模块中使用 my_counter 这个 per-CPU 变量了。如果你有其他具体的需求或问题,请随时告诉我。
  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
`DEFINE_PER_CPU_SHARED_ALIGNED()` 是 Linux 内核中用于定义一个共享的、对齐的 per-CPU 变量的宏。在多核系统中,每个 CPU 都有自己的寄存器和缓存,这些资源可以用于存储一些与 CPU 相关的变量,以便提高访问速度和并发性。`per-CPU` 变量就是一种特殊的变量类型,它可以让每个 CPU 都拥有独立的变量副本,并且可以通过一些特殊的函数接口进行访问。这样,就可以避免多个 CPU 访问同一个变量时的竞争和同步问题。 `DEFINE_PER_CPU_SHARED_ALIGNED()` 宏用于定义一个共享的、对齐的 per-CPU 变量。它包含三个参数: - `type`:变量的数据类型。 - `name`:变量的名称,可以是任意合法的 C 语言标识符。 - `align`:变量需要对齐的字节数。通常使用 `sizeof(type)` 来作为对齐字节数。 宏的具体实现比较复杂,它会使用一些内核中的数据结构和机制来实现 per-CPU 变量的定义和访问。具体来说,它会定义一个 `__typeof__(type)` 类型的指针数组,数组的大小等于 CPU 的个数。然后,它会使用 `__aligned__(align)` 宏来对数组进行对齐,以保证每个变量副本都被正确地对齐。最后,宏会定义一个访问变量的宏,以便在内核代码中使用。 使用 `DEFINE_PER_CPU_SHARED_ALIGNED()` 宏定义的 per-CPU 变量可以通过一些特殊的函数接口进行访问,如 `get_cpu_var()`、`put_cpu_var()` 和 `this_cpu_ptr()` 等等。这些函数会根据当前 CPU 的编号来选择相应的变量副本,并返回对应的指针。这样,每个 CPU 都可以独立地访问自己的变量副本,而不会产生竞争和同步问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fulinux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值