多核中percpu的数据分配

linux2.6 为了方便创建和操作每个CPU数据,引进了新的操作接口,percpu(),该接口简化了创建了操作每个CPU的数据。

定义于<linux/percpu.h> 和<mm/slab.c> 中

1. 定义和声明每个CPU变量:

DEFINE_PER_CPU(type, name);
这语句为系统的每个CPU都创建了一个类型为type,名字为name的变量。

如果需要在别处声明此变量,以防编译时的警告,可使用下面的宏:

DECLARE_PER_CPU(type, name);
2. 操作每个CPU的变量和指针:
get_cpu_var(name);  //返回当前处理器上的指定变量name的值, 同时将他禁止抢占;

put_cpu_var(name); //与get_cpu_var(name)相对应,重新激活抢占;

/*
 * Must be an lvalue. Since @var must be a simple identifier,
 * we force a syntax error here if it isn't.
 */
#define get_cpu_var(var) (*({				\
	preempt_disable();				\
	&__get_cpu_var(var); }))

/*
 * The weird & is necessary because sparse considers (void)(var) to be
 * a direct dereference of percpu variable (var).
 */
#define put_cpu_var(var) do {				\
	(void)&(var);					\
	preempt_enable();				\
} while (0)

通过指针来操作每个CPU的数据:

get_cpu_ptr(var); --- 返回一个void类型的指针,指向CPU ptr处的数据

put_cpu_ptr(var); --- 操作完成后,重新激活内核抢占。

#define get_cpu_ptr(var) ({				\
	preempt_disable();				\
	this_cpu_ptr(var); })

#define put_cpu_ptr(var) do {				\
	(void)(var);					\
	preempt_enable();				\
} while (0)
3. 获得别的处理器上的name变量的值

per_cpu(name, cpu) ;   //返回别的处理器cpu上变量name的值;

4. 给系统中每个处理器分配一个指定类型的对象: alloc_percpu();

#define alloc_percpu(type)	\
	(typeof(type) __percpu *)__alloc_percpu(sizeof(type), __alignof__(type))
/**
 * __alloc_percpu - allocate dynamic percpu area
 * @size: size of area to allocate in bytes
 * @align: alignment of area (max PAGE_SIZE)
 *
 * Allocate zero-filled percpu area of @size bytes aligned at @align.
 * Might sleep.  Might trigger writeouts.
 *
 * CONTEXT:
 * Does GFP_KERNEL allocation.
 *
 * RETURNS:
 * Percpu pointer to the allocated area on success, NULL on failure.
 */
void __percpu *__alloc_percpu(size_t size, size_t align)
{
	return pcpu_alloc(size, align, false);
}
EXPORT_SYMBOL_GPL(__alloc_percpu);
参数为type, 就是指定的需要分配的类型,通过类型,可以得出__alloc_percpu()的两个参数:

size =  sizeof(type);

align = __alignof__(type);

__alignof__()是gcc的一个功能,它会返回指定类型或lvalue所需的对齐字节数。

相应的释放所有处理器上指定的每个CPU数据:free_percpu();

/**
 * free_percpu - free percpu area
 * @ptr: pointer to area to free
 *
 * Free percpu area @ptr.
 *
 * CONTEXT:
 * Can be called from atomic context.
 */
void free_percpu(void __percpu *ptr)
{
	void *addr;
	struct pcpu_chunk *chunk;
	unsigned long flags;
	int off;

	if (!ptr)
		return;

	addr = __pcpu_ptr_to_addr(ptr);

	spin_lock_irqsave(&pcpu_lock, flags);

	chunk = pcpu_chunk_addr_search(addr);
	off = addr - chunk->base_addr;

	pcpu_free_area(chunk, off);

	/* if there are more than one fully free chunks, wake up grim reaper */
	if (chunk->free_size == pcpu_unit_size) {
		struct pcpu_chunk *pos;

		list_for_each_entry(pos, &pcpu_slot[pcpu_nr_slots - 1], list)
			if (pos != chunk) {
				schedule_work(&pcpu_reclaim_work);
				break;
			}
	}

	spin_unlock_irqrestore(&pcpu_lock, flags);
}
EXPORT_SYMBOL_GPL(free_percpu);

5. get_cpu()/put_cpu() --- 获得处理器编号

get_cpu() 在返回当前处理器编号之前,先回关闭内核抢占。

put_cpu() 重新打开内核抢占。

函数定义如下:

#define get_cpu()		({ preempt_disable(); smp_processor_id(); })
#define put_cpu()		preempt_enable()
使用案例如下:
int cpu;

cpu = get_cpu();   //禁止抢占内核,并将CPU设置为当前处理器。

//对每个处理器的数据进行操作,

put_cpu();   //使能内核抢占



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值