每-CPU变量

现代SMP操作系统使用每-CPU数据——这些数据对每个处理器都是唯一的。通常,每-CPU数据存储在一个数组中。数组中的每项对应系统上的一个可能的处理器。如:

unsigned long my_percpu[NR_CPUS];

访问的方式如下:

int cpu;

cpu = get_cpu(); /* get current processor and disable kernel preemption */

my_percpu[cpu]++; /* ... or whatever */

printk(“my_percpu on cpu=%d is %lu\n”, cpu, my_percpu[cpu]);

put_cpu(); /* enable kernel preemption */

 

访问每-CPU数据唯一需要考虑的就是内核抢占。内核抢占导致了两个问题,如下所示:

l  如果运行的代码被抢占并被调度到另一个处理器上运行,cpu变量不再合法,因为它指向了错误的处理器(通常,代码在获得当前处理器后不能睡眠)。

l  如果另一个任务抢占了当前运行的代码,它可能并发地访问相同处理器上的my_percpu,从而导致了一个竞态发生。

然而,任何担心都是多余的,因为get_cpu()在返回处理器编号的同时,也会禁用内核抢占。put_cpu()则恢复内核抢占。注意:如果使用smp_processor_id()来获取当前处理器的编号,内核抢占则并不会被禁止。

新的percpu接口(2.6后)

2.6内核引入了一个新的接口,称为percpu,,用于创建和操作每-CPU数据。该接口扩展了上述例子。新的接口更简单,但旧的接口依然有效。

定义:

DEFINE_PER_CPU(type, name);

声明:

DECLARE_PER_CPU(type, name);

操作变量函数:

get_cpu_var()   put_cpu_var()

如:

get_cpu_var(name)++; /* increment name on this processor,同时禁用内核抢占 */

put_cpu_var(name); /* done; enable kernel preemption */

访问另一个处理器的每-CPU数据:

per_cpu(name, cpu)++; /* increment name on the given processor */,注意,该函数并没有禁用内核抢占。

动态分配每-CPU数据

内核实现了一个动态分配器,类似于kmalloc(),用于创建每-CPU数据。这些函数原型如下:

void *alloc_percpu(type); /* a macro */

void *__alloc_percpu(size_t size, size_t align);

void free_percpu(const void *);

get_cpu_var(ptr); /* return a void pointer to this processor’s copy of ptr */

put_cpu_var(ptr); /* done; enable kernel preemption */

使用例子如下:

void*percpu_ptr;

unsignedlong*foo;

percpu_ptr=alloc_percpu(unsignedlong);

if(!ptr)

/*errorallocatingmemory..*/

foo=get_cpu_var(percpu_ptr);

/*manipulatefoo..*/

put_cpu_var(percpu_ptr);

 

你可能感兴趣的:(每-CPU变量)