8-2.前瞻快取(Lookaside Caches)
驅動需要一次又一次配置許多一樣大小的物件時,利用此機制將相同大小的物件集中在相同的集散區,再從裡面去配置記憶體,驅動程式不必為了刻意使用前瞻快取,而調整自己的記憶體存取行為,但USB以及SCSI此類裝置會使用此機制。
核心裡的快取管理系統,有時被稱為"slab allocator",它的函式宣告於<linux/slab.h>
代表快取的記憶體物件型別是kmem_cache_t,透過kmem_cache_create()來建立快取物件。
kmem_cache_t *kmem_cache_create(const char *name,size_t size,size_t offset,unsigned long flags,void (*constructor)(void*,kmem_cache_t *,unsigned long flags),void (*destructor)(void*,kmem_cache_t *,unsigned long flags));
name
是一個同時代表函式與快取的符號,可以用來追求問題的資訊
offset
是第一個物件在記憶頁的起始位置
flags
控制配置方式:
SLAB_NO_REAP
保護快取不因系統短缺記憶體而縮減其容量
SLAB_HWCACHE_ALIGN
此旗標要求每個資料物件都要對齊一條快取線
SLAB_CACHE_DMA
要求每一個資料物件都配置在DMA可存取的記憶體。
constructor
與destructor
兩者都是選擇性引數,前者指向一個負責指向一個負責物件初始化工作的函式,後者所指的函式,會在物件的記憶體被釋放回系統之前被呼叫一次。為了方便可以使用同一個函式來同時兼任建構式與解構式,為了函式知道自己要負責何種任務,slab_allocator會傳遞SLAB_CTOR_CONSTRUCTOR旗標給建構式。在成功建立物件的快取之後,就可以呼叫kmem_cache_alloc()來配置物件:
void *kmem_cache_alloc(kmem_cache_t *cache,int flags);
如果要釋放一個物件,使用kmem_cache_free():
void kmem_cache_free(kmem_cache_t *cache,const void *obj);
當驅動程式使用完快取,可用下函式釋放:
int kmem_cache_destroy(kmem_cache_t *cache);
kmem_cache_destroy()只有在所有從快取配置出去的物件歸還之後,才會成功銷毀快取。
記憶池
核心中有些關鍵情況絕不容許記憶體配置失敗,為了確保這些關鍵情況絕對可配置到,核心開發了一種抽象觀念稱為記憶池(memory pool)。實際上記憶池與前瞻快取很像,唯一差別記憶池總是會保持一些可用的記憶體,以應付緊急狀況。
記憶體的型別為mempool_t(定義於<linux/mempool.h>
),可以用mempool_create()建立:
mempool_t *mempool_create(int min_nr,mempool_*alloc_t *alloc_fn,mempool_free_t *free_fn,void *pool_data);
min_nr代表記憶池中至少保留多少個物件配置量。物件的實際配置與釋放,是由alloc_fn與free_fn型別的函式負責,這兩個型別的定義如下:
typedef void *(mempool_alloc_t)(int gfp_mask,void *pool_data);
typedef void *(mempool_free_t)(void *element,void *pool_data);
mempool_create()所收到的最後一個引數(pool_data),會傳給flloc_fn()與free_fn()。
記憶體配置通常可以使用slab allocator來代勞,設定記憶池的程式片段,看起來像下面這樣:
cache = kmem_cache_creat();
pool = mempool_create(MY_POOL_MINIMUN,mempool_alloc_slab,mempool_free_slab,cache);
一旦建立好記憶池後,可用下列這組函式來配置,釋放物件:
void *mempool_alloc(mempool_t *pool,int gfp_mask);
void *mempool_free(void *element,mempool_t *pool);
記憶池容量可於下列函式來改變:
int mempool_resize(mempool_t *pool,int new_min_nr,int gfp_mask);
不再需要記憶池,就將其還給系統:
void mempool_destroy(mempool_t *pool);