percpu 变量总结

percpu 可以的接口可以分为新接口和旧接口

目前旧借口的sample code如下:

	int cpu;

	tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
	if (!tuners)
		return -ENOMEM;

	cpu = get_cpu();
	idle_time = get_cpu_idle_time_us(cpu, NULL);
	put_cpu();
这code 中可以通过get_cpu 得到当前cpu
#define get_cpu()		({ preempt_disable(); smp_processor_id(); })
可以看到get_cpu 首先会通过preempt_disable 禁止内核抢占,然后调用smp_processor_id 返回当前cpu id。
而与之对应的put_cpu 就是使能内核抢占.#define put_cpu()		preempt_enable()

新的percpu接口可以分为静态申请和动态申请
静态percpu 可以通过DECLARE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); 来申请
可以通过			fps = &per_cpu(bnx2fc_percpu, cpu);来读到这个percpu的数据到fps中
而这里的#define per_cpu(var, cpu)	(*per_cpu_ptr(&(var), cpu))
可见per_cpu 只是per_cpu_ptr的一个包装,因此能用per_cpu访问的,都可以通过per_cpu_ptr 来访问
#define per_cpu_ptr(ptr, cpu)						\
({									\
	__verify_pcpu_ptr(ptr);						\
	SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)));			\
})


例如下例子中就通过per_cpu_ptr得到acpi_perf_data 这个变量在cpu上的值
static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
	perf = per_cpu_ptr(acpi_perf_data, cpu);

}
更进一步是采用get_cpu_ptr得到percpu的值
#define get_cpu_ptr(var)						\
({									\
	preempt_disable();						\
	this_cpu_ptr(var);						\
})
get_cpu_ptr 默认是获取当前cpu上的值
int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
	int b, int offset, int length, struct squashfs_page_actor *output)
{
	struct squashfs_stream *stream = get_cpu_ptr(percpu);
}

除了静态定义外,percpu变量可以在运行是创建
alloc_percpu 可以在运行是创建percpu变量,释放percpu占用的空间可以采用free_percpu
使用的例子如下:
static __net_init int ipv4_mib_init_net(struct net *net)
{
	int i;

	net->mib.tcp_statistics = alloc_percpu(struct tcp_mib);
	if (!net->mib.tcp_statistics)
		goto err_tcp_mib;
	net->mib.ip_statistics = alloc_percpu(struct ipstats_mib);
	if (!net->mib.ip_statistics)
		goto err_ip_mib;

	for_each_possible_cpu(i) {
		struct ipstats_mib *af_inet_stats;
		af_inet_stats = per_cpu_ptr(net->mib.ip_statistics, i);
		u64_stats_init(&af_inet_stats->syncp);
	}

	net->mib.net_statistics = alloc_percpu(struct linux_mib);
	if (!net->mib.net_statistics)
		goto err_net_mib;
	net->mib.udp_statistics = alloc_percpu(struct udp_mib);
	if (!net->mib.udp_statistics)
		goto err_udp_mib;
	net->mib.udplite_statistics = alloc_percpu(struct udp_mib);
	if (!net->mib.udplite_statistics)
		goto err_udplite_mib;
	net->mib.icmp_statistics = alloc_percpu(struct icmp_mib);
	if (!net->mib.icmp_statistics)
		goto err_icmp_mib;
	net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib),
					      GFP_KERNEL);
	if (!net->mib.icmpmsg_statistics)
		goto err_icmpmsg_mib;

	tcp_mib_init(net);
	return 0;

err_icmpmsg_mib:
	free_percpu(net->mib.icmp_statistics);
err_icmp_mib:
	free_percpu(net->mib.udplite_statistics);
err_udplite_mib:
	free_percpu(net->mib.udp_statistics);
err_udp_mib:
	free_percpu(net->mib.net_statistics);
err_net_mib:
	free_percpu(net->mib.ip_statistics);
err_ip_mib:
	free_percpu(net->mib.tcp_statistics);
err_tcp_mib:
	return -ENOMEM;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值