支援smp的現代作業系統使用每個cpu上的資料,對於給定的處理器其資料是唯一的。一般來說,每個cpu的資料存放在乙個陣列中。陣列中的每一項對應著系統上乙個存在的處理器。當預處理器號確定這個陣列的當前元素:
unsigned long my_percpu[nr_cpus];
然後按如下方式訪問它:
int cpu;
cpu = get_cpu();//獲得當預處理器,並禁止核心搶占
my_percpu[cpu]++;//也可以是其他操作
put_cpu();//啟用核心搶占
注意,上面的**中沒有出現鎖,因為所操作的資料對當預處理器來說是唯一的,除了當預處理器沒有其他處理器可以接觸這個資料,不存在併發訪問。核心搶占成了唯一要關注的問題:
1. 如果你的**被其他處理器搶占並重新排程,那麼這時cpu變數會無效,因為它指向了錯誤的處理器(通常,**獲得當預處理器後是不能睡眠的)。
2. 如果別的任務搶占了你的**,那麼有可能在同乙個處理器上發生併發訪問my_percpu的情況。
其實不必擔心,因為在獲取當預處理器號,即呼叫get_cpu()時,就已經禁止了核心搶占。相應地,smp_processor_id()在呼叫put_cpu()時又會重新啟用當預處理器號。注意,如果使用smp_processor_id()的呼叫來獲得當預處理器號,只要使用上述方法來包含資料安全,那麼核心搶占並不需要自己去禁止。
2.6核心為了方便建立和操作每個cpu資料,從而引進了新的操作介面,稱作percpu。標頭檔案宣告了所有的介面操作例程,可以在檔案mm/slab.c和asm/percpu.h中找到它們的定義。
1. 編譯時的每個cpu資料
在編譯時定義每個cpu變數: 在中
#ifdef config_smp
/* separate out the type, so (int[3], foo) works. */
#define define_per_cpu(type, name) /
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
#else /* ! smp */
#define define_per_cpu(type, name) /
__typeof__(type) per_cpu__##name
如果需要在別處宣告變數,以防範編譯時警告,可以使用下面的巨集: 在中
#define declare_per_cpu(type, name) extern __typeof__(type) per_cpu__##name
呼叫get_cpu_var()返回當預處理器上的指定變數,同時它將禁止搶占;另一方面put_cpu_var()將相應地重新啟用搶占。 在中
/** must be an lvalue. since @var must be a ****** identifier,
* we force a syntax error here if it isn't.
*/#define get_cpu_var(var) (*())
#define put_cpu_var(var) preempt_enable()
也可以通過per_cpu()函式獲得別的處理器上的每個cpu資料,使用時要小心,因為per_cpu()函式既不會禁止核心搶占,也不會提供任何形式的鎖保護。如果一些處理器可以接觸到其他處理器上的資料,就必須給資料上鎖: 在中
#ifdef config_smp
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*())
#else /* ! smp */
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
這些編譯時每個cpu資料的例子並不能在模組內使用,因為連線程式實際上將它們建立在乙個惟一的可執行段中(.data.percpu),如果需要從模組中訪問每個cpu資料,或者如果需要動態建立這些資料,可以看下一節。
核心實現每個cpu資料的動態分配方法類似與kmalloc()。
在中/* (legacy) inte***ce for use without cpu hotplug handling */
/*size是實際要分配的位元組數 */
#define __alloc_percpu(size) percpu_alloc_mask((size), gfp_kernel, /
cpu_possible_map)
/* 給系統中的每個處理器分配乙個指定型別物件的例項,返回乙個指標,用於簡介引用動態建立的每個cpu資料*/
#define alloc_percpu(type) (type *)__alloc_percpu(sizeof(type))
/* 釋放所有處理器上指定的每個cpu資料*/
#define free_percpu(ptr) percpu_free((ptr))
#define percpu_alloc_mask(size, gfp, mask) /
__percpu_alloc_mask((size), (gfp), &(mask))
#ifdef config_smp
extern
void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask);
#else /* config_smp */
static __always_inline void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
核心提供兩個巨集來利用指標獲取每個cpu資料:
最後,函式per_cpu_ptr()返回了指定處理器上的惟一資料。這個函式不會禁止核心搶占,如果需要訪問另外的處理器資料,一定要給資料加鎖:
#define per_cpu_ptr(ptr, cpu) percpu_ptr((ptr), (cpu))
#ifdef config_smp
struct percpu_data ;
#define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
/* * use this to get to a cpu's version of the per-cpu object dynamically
* allocated. non-atomic access to the current cpu's version should
* probably be combined with get_cpu()/put_cpu().
*/#define percpu_ptr(ptr, cpu) /
()#else /* config_smp */
#define percpu_ptr(ptr, cpu) ()
首先,減少了資料鎖定。按照每個處理器訪問每個cpu資料的邏輯,可以不再需要任何鎖。「只有這個處理器能訪問這個資料」純粹是乙個程式設計約定,需要程式設計者確保本地處理器只會訪問它自己的唯一資料。
第二,使用每個cpu資料可以大大減少快取失效。失效發生在處理器試圖使它們的快取保持同步時。如果乙個處理器操作某個資料,而資料又存放在其他處理器上,那麼存放該資料的處理器必須清理或重新整理自己的快取。持續不斷的快取失效稱為快取抖動。使用每個cpu資料將減少快取抖動。percpu介面快取--對齊(cache-aligns)所有資料,以便確保在訪問乙個處理器的資料時不會將另乙個處理器的資料帶入同乙個快取線上。
每個cpu資料在中斷上下文或程序上下文中使用都很安全,但是不能在訪問每個cpu資料過程中睡眠。它的唯一要求就是禁止核心搶占。
7 記憶體管理
0xc0000000 128mb 8mbpagetable init ram896mb 0xc0000000 1g,送去最後的 128mb 剩下896mb ramram 大小在896 4096mb 之間時,核心只能根據頁表定址到其中的 896mb 初始化階段就將 896mb ram128m 0xc0...
7記憶體管理 MRC
記憶體管理,即記憶體裡各個物件的管理,即記憶體裡各個物件的生命週期的管理,從物件導向的角度看 預設為1,即有一滴的生命血液,若為0就會死去 自己管理自己,自己在方法最後,要給自己release一下,不然自己死不了 1重寫遺書方法 在裡面把屬性物件釋放,2重寫set方法,裡面若前後值不同,就釋放舊值,...
7 php 記憶體洩漏 PHP 記憶體管理
php 的記憶體管理來自於 zend 引擎。php 的記憶體管理與預防記憶體洩漏緊密關聯。有關執行緒內全域性資料處理的資訊請參見作為執行緒隔離設施的執行緒安全的資源管理器。此外,zend 引擎要面對乙個十分特殊的使用模式 在一段比較短的時間內,許多 zval 結構大小的記憶體塊和其他的小記憶體塊被申...