Linux SMP 多核调用示例
在多core系统中,系统启动后内核将会在一个core上执行,且会在不同core上进行调度。即内核模块(驱动)加载只会在一个core中执行一次初始化。那么需要在所有core,或某个特殊的core执行那么我们需要smp提供的多核接口。
smp相关api
在linux/smp.h中定义了多core调用的函数以及相关的数据结构。
在所有的core上执行函数func,info是传递给func的参数。
void on_each_cpu(smp_call_func_t func, void *info, int wait);
在给定cpumask中所有的core上执行函数func,info是传递给func的参数。
void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func, void *info, bool wait);
除了调用core外所有的core都执行
void smp_call_function(smp_call_func_t func, void *info, int wait);
在指定的cpumask所对应的core上执行,但是需要除去当前调用的core。
void smp_call_function_many(const struct cpumask *mask, smp_call_func_t func, void *info, bool wait);
在指定的cpumask所对应的core中的其中一个core上执行一次
int smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, void *info, int wait);
在指定的cpuid上执行一次
int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, int wait);
在内核空间中,定义了几个全局cpumask变量。
cpu_possible_mask- has bit ‘cpu’ set iff cpu is populatable
cpu_present_mask - has bit ‘cpu’ set iff cpu is populated
cpu_online_mask - has bit ‘cpu’ set iff cpu available to scheduler
cpu_active_mask - has bit ‘cpu’ set iff cpu available to migration
示例// smp-test.c
#include
#include
#include
#include
/*
linux/smp.h
Call a function on all processors
void on_each_cpu(smp_call_func_t func, void *info, int wait);
Call a function on processors specified by mask, which might include
the local one.
void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
void *info, bool wait);
Call a function on all other processors
void smp_call_function(smp_call_func_t func, void *info, int wait);
void smp_call_function_many(const struct cpumask *mask,
smp_call_func_t func, void *info, bool wait);
int smp_call_function_any(const struct cpumask *mask,
smp_call_func_t func, void *info, int wait);
int smp_call_function_single(int cpuid, smp_call_func_t func, void *info,
int wait);
* cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
* cpu_present_mask - has bit 'cpu' set iff cpu is populated
* cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
* cpu_active_mask - has bit 'cpu' set iff cpu available to migration
*/
static void smp_print_id(void *t)
{
unsigned int cur_cpu = smp_processor_id();
printk("cur cpuid: %d, %d\n", cur_cpu, get_cpu());
}
static int __init smp_test_init(void)
{
cpumask_t cpu_mask;
int cpu_id = get_cpu();
int res = 0;
// 每一个core都执行
on_each_cpu(smp_print_id, NULL, 1);
printk("finish on each cpu\n");
// cpu_online_mask 当前在线的core掩码
on_each_cpu_mask(cpu_online_mask, smp_print_id, NULL, 1);
printk("finish on each cpu cpu_online_mask [0x%lx]\n", cpu_online_mask->bits[0]);
// 根据指定的掩码在对应的core上执行
cpu_mask.bits[0] = 0xf;
on_each_cpu_mask(&cpu_mask, smp_print_id, NULL, 1);
printk("finish on each cpu mask [0x%lx]\n", cpu_mask.bits[0]);
// 除了当前core,其他core都要执行
smp_call_function(smp_print_id, NULL, 1);
printk("smp_call_function finish cur_cpu %d\n", cpu_id);
// 在给定的掩码对应的core上执行,除了当前core
cpu_mask.bits[0] |= 1 << cpu_id;
smp_call_function_many(&cpu_mask, smp_print_id, NULL, 1);
printk("smp_call_function_many cpu mask cur_cpu %d [0x%lx]\n", cpu_id, cpu_mask.bits[0]);
// 给定cpumask对应core中选择一个core执行一次
// cpu_mask.bits[0] = 1 << cpu_id; // 测试是否会在当前核中执行
res = smp_call_function_any(&cpu_mask, smp_print_id, NULL, 1);
printk("smp_call_function_any cur_cpu %d res [%d] mask[0x%lx]\n", cpu_id, res, cpu_mask.bits[0]);
// 指定core执行一次
res = smp_call_function_single(cpu_id, smp_print_id, NULL, 1);
printk("smp_call_function_single cur_cpu %d res [%d] mask[0x%lx]\n", cpu_id, res, cpu_mask.bits[0]);
return 0;
}
static void __exit smp_test_exit(void)
{
printk(KERN_DEBUG "byebye\n");
}
module_init(smp_test_init);
module_exit(smp_test_exit);
MODULE_AUTHOR("ystlong@163.com>");
MODULE_DESCRIPTION("Linux Kernel sysfs kobj test");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");