免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 682 | 回复: 0
打印 上一主题 下一主题

per cpu data 分析 [not digested] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-02-18 16:42 |只看该作者 |倒序浏览
per cpu data 分析 . 转载 http://note.ssreader.com/show_topic.asp?Topicid=214192&forumid=6
[color="red"]Linux 2.6 内核 per cpu data 分析
在arch/i386/kernel/vmlinux.lds中有
  /* will be freed after init */
  . = ALIGN(4096);                /* Init code and data */
  __init_begin = .;
  /* 此处省略若干行:) */
  
  . = ALIGN(32);
  __per_cpu_start = .;
  .data.percpu  : { *(.data.percpu) }
  __per_cpu_end = .;
  . = ALIGN(4096);
  __init_end = .;
  /* freed after init ends here */
这说明__per_cpu_start和__per_cpu_end标识.data.percpu这个section的开头和结尾
并且,整个.data.percpu这个section都在__init_begin和__init_end之间,
也就是说,该section所占内存会在系统启动后释放(free)掉
因为有
#define DEFINE_PER_CPU(type, name)     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
所以
static DEFINE_PER_CPU(struct runqueue, runqueues);
会扩展成
__attribute__((__section__(".data.percpu"))) __typeof__(struct runqueue) per_cpu__runqueues;
也就是在.data.percpu这个section中定义了一个变量per_cpu__runqueues,其类型是struct runqueue。
事实上,这里所谓的变量per_cpu__runqueues,其实就是相对于__per_cpu_start的偏移量。
系统启动后,在start_kernel()中会调用如下函数
unsigned long __per_cpu_offset[NR_CPUS];
static void __init setup_per_cpu_areas(void)
{
        unsigned long size, i;
        char *ptr;
        /* Created by linker magic */
        extern char __per_cpu_start[], __per_cpu_end[];
        /* Copy section for each CPU (we discard the original) */
        size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
#ifdef CONFIG_MODULES
        if (size < PERCPU_ENOUGH_ROOM)
                size = PERCPU_ENOUGH_ROOM;
#endif
        ptr = alloc_bootmem(size * NR_CPUS);
        for (i = 0; i < NR_CPUS; i++, ptr += size) {
                __per_cpu_offset = ptr - __per_cpu_start;
                memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
        }
}
在该函数中,为每个CPU分配一段内存,并将.data.percpu中的数据拷贝到其中,
每个CPU各有一份,其中CPU n对应的专有数据区的首地址为__per_cpu_offset[n]。
这样,前述相应于__per_cpu_start的偏移量per_cpu__runqueues就变成了相应于
__per_cpu_offset[n]的偏移量,这样.data.percpu这个section在系统初始化后
就可以释放了。
再看如何存取per cpu的变量
/* This macro obfuscates arithmetic on a variable address so that gcc
   shouldn't recognize the original var, and make assumptions about it */
#define
RELOC_HIDE(ptr, off) ({ unsigned long __ptr; __asm__ ("" : "=g"(__ptr)
: "0"(ptr)); (typeof(ptr)) (__ptr + (off)); })
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
#define __get_cpu_var(var) per_cpu(var, smp_processor_id())
#define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); }))
对于__get_cpu_var(runqueues),将等效地扩展为
__per_cpu_offset[smp_processor_id()] + per_cpu__runqueues
并且是一个lvalue,也就是说可以进行赋值操作。
这正好是上述对应CPU的专有数据区的首地址加上对应偏移量per_cpu__runqueues,
由于不同的per cpu变量有不同的偏移量,并且不同的CPU其专有数据区首地址不同,
因此,通过__get_cpu_var()便访问到了不同的变量。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/38057/showart_479996.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP