网站公告列表

  没有公告

加入收藏
设为首页
联系本站
您现在的位置: AnalogCN安诺电子 >> 文章 >> 技术交流 >> 文章正文
  uclinux-2008r1(bf561)内核中的per_cpu           ★★★ 【字体:
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条。评论内容只代表网友观点,与本站立场无关!)
    版权所有:AnalogCN安诺电子 湘ICP备06016315号