日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DEFINE_PER_CPU

發(fā)布時間:2023/11/29 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DEFINE_PER_CPU 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉自 http://www.unixresources.net/linux/clf/linuxK/archive/00/00/47/91/479165.html

首先,在arch/i386/kernel/vmlinux.lds中有


/*will be free after init*/

.=ALIGN(4096);

__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所占內(nèi)存會在系統(tǒng)啟動后釋放(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,
其實就是一個偏移量,標識該變量的地址。

--------------------
其次,系統(tǒng)啟動后,在start_kernel()中會調(diào)用如下函數(shù)

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_MODULESif (size < PERCPU_ENOUGH_ROOM)size = PERCPU_ENOUGH_ROOM;#endifptr = alloc_bootmem(size * NR_CPUS);for (i = 0; i < NR_CPUS; i++, ptr += size) {__per_cpu_offset[i] = ptr - __per_cpu_start;memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);}}

在該函數(shù)中,為每個CPU分配一段專有數(shù)據(jù)區(qū),并將.data.percpu中的數(shù)據(jù)拷貝到其中,
每個CPU各有一份。由于數(shù)據(jù)從__per_cpu_start處轉移到各CPU自己的專有數(shù)據(jù)區(qū)中了,
因此存取其中的變量就不能再用原先的值了,比如存取per_cpu__runqueues
就不能再用per_cpu__runqueues了,需要做一個偏移量的調(diào)整,
即需要加上各CPU自己的專有數(shù)據(jù)區(qū)首地址相對于__per_cpu_start的偏移量。
在這里也就是__per_cpu_offset[i],其中CPU i的專有數(shù)據(jù)區(qū)相對于
__per_cpu_start的偏移量為__per_cpu_offset[i]。
這樣,就可以方便地計算專有數(shù)據(jù)區(qū)中各變量的新地址,比如對于per_cpu_runqueues,
其新地址即變成per_cpu_runqueues+__per_cpu_offset[i]。

經(jīng)過這樣的處理,.data.percpu這個section在系統(tǒng)初始化后就可以釋放了。

--------------------
再看如何存取per cpu的變量

/* This macro obfuscates arithmetic on a variable address so that gccshouldn'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,也就是說可以進行賦值操作。
這正好是上述per_cpu__runqueues變量在對應CPU的專有數(shù)據(jù)區(qū)中的新地址。

由于不同的per cpu變量有不同的偏移量,并且不同的CPU其專有數(shù)據(jù)區(qū)首地址不同,
因此,通過__get_cpu_var()便訪問到了不同的變量。

--END

總結

以上是生活随笔為你收集整理的DEFINE_PER_CPU的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。