![]() |
|
||||||||||||||
| | 首页 | 新闻 | 文库 | 方案 | 技术 | 独家 | 座谈 | 下载 | 图库 | 开发板 | 仿真器 | 邮购 | VIP会员 | 芯片代购 | 客户评价 | | ||
|
||
|
|||||
| uclinux-2008r1(bf561)内核中的per_cpu | |||||
作者:快乐虾 文章来源:http://blog.csdn.net/lights_joy 点击数: 更新时间:2008-5-21 ![]() |
|||||
|
当内核不需要支持smp的时候,per_cpu是无关紧要的,因为数据只有一份。但是当需要支持smp的时候,per_cpu就显示相当重要了,它可以为每个CPU定义属于自己的专有数据。
在kernel/shed.c中有这样一个定义:
/*
* This is the main, per-CPU runqueue data structure.
*
* Locking rule: those places that want to lock multiple runqueues
* (such as the load balancing or the thread migration code), lock
* acquire operations must be ordered by ascending &runqueue.
*/
struct rq {
…
};
static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
从注释中可以看出rq这个结构体保存了运行时的任务队列信息,当然每个CPU都有自己的任务队列,因而自然需要为每个CPU都定义一个私有的数据。
其中DEFINE_PER_CPU的定义在include/asm-generic/percpu.h中:
/* Separate out the type, so (int[3], foo) works. */
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
满简单的,无非就是定义一个指定类型的变量,再将它放到一个特定的数据段中。为此,我们需要在ldf文件中添加这样一段:
//.percpu
INPUT_SECTION_ALIGN(64)
. = (. + 63) / 64 * 64;
___per_cpu_start = .;
INPUT_SECTIONS($LIBRARIES_UCLINUX(.data.percpu))
___per_cpu_end = .;
到这里,我们还看不出是如何为每个CPU保留自己的数据的。
在start_kernel()函数中有这样一个调用:
setup_per_cpu_areas();
这个函数实现如下所示:
unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(__per_cpu_offset);
static void __init setup_per_cpu_areas(void)
{
unsigned long size, i;
char *ptr;
unsigned long nr_possible_cpus = num_possible_cpus();
/* Copy section for each CPU (we discard the original) */
size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
ptr = alloc_bootmem_pages(size * nr_possible_cpus);
for_each_possible_cpu(i) {
__per_cpu_offset[i] = ptr - __per_cpu_start;
memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
ptr += size;
}
}
也就是说,A核从内核为自己申请了一块空间,把percpu这个段的内容复制了一遍,自然也就有了一块自己的数据。当然,当内核运行到这里的时候,B核还没有启动, for_each_possible_cpu只会执行一次,但是可以想像,当B核启动时,应该也会将这个段的内容复制一遍。
在这里,还使用了一个__per_cpu_offset数组来保存每个核的私有数据离__per_cpu_start的偏移量。
当bf561核需要访问自己的私有数据时,它会这样:
volatile struct rq *rq;
rq = cpu_rq(i);
这里,cpu_rq定义为:
#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
而per_cpu的定义则为:
# define RELOC_HIDE(ptr, off) \
({ unsigned long __ptr; \
__ptr = (unsigned long) (ptr); \
(typeof(ptr)) (__ptr + (off)); })
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*({ \
extern int simple_identifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
从而保证访问的是自己的私有数据,而不是.data.per_cpu这个段中的数据内容。
|
|||||
| 文章录入:admin 责任编辑:admin | |||||
| 【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口】 | |||||
| 最新热点 | 最新推荐 | 相关文章 | ||
| 前置放大器在移动医疗服务系 便携式多通道大容量生理信号 防腐监测仪的设计与应用 基于AD1674的酶标仪的设计 基于C/S模式的JRTPLIB库的测 ffmpeg与jrtplib相结合应用 blackfin模拟摄像头驱动中的 可编程逻辑在数字信号处理系 发现VDSP4.5一个BUG:单步调 VDSP5.0双核工程下sml3中的变 |
| 网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!) |
| | 本站介绍 | 合作联络 | 欢迎投稿 | 广告业务 | 网站地图 | 设为首页 | 加入收藏 | 友情链接 | 网站公告 | 联系我们 | | |||
|