kernel中的mempool机制

来源:互联网 发布:2017淘宝评价排序规则 编辑:程序博客网 时间:2024/06/05 22:59
mempool 为了防止某些情况下分配内存不能失败而采用的技术。实现思路是会预留一定数量大小相等的内存块来备用。其源码在/mm/mempool.c中.在kernel中通过typedef struct mempool_s {spinlock_t lock;int min_nr;/* nr of elements at *elements */int curr_nr;/* Current nr of elements at *elements */void **elements;void *pool_data;mempool_alloc_t *alloc;mempool_free_t *free;wait_queue_head_t wait;} mempool_t;来表示一个mempool。使用mempool的时候必须先调用mempool_create来create 一个memory poolmempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,mempool_free_t *free_fn, void *pool_data){return mempool_create_node(min_nr,alloc_fn,free_fn, pool_data,   GFP_KERNEL, NUMA_NO_NODE);}mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,       mempool_free_t *free_fn, void *pool_data,       gfp_t gfp_mask, int node_id){mempool_t *pool;pool = kzalloc_node(sizeof(*pool), gfp_mask, node_id);if (!pool)return NULL;//可以看到这里预留了min_nr个sizeof(void *)的size,简单举例下如果是64 位系统的话sizeof(void *) 是8个byte,假如min_nr等于1的话,在create的时候就预留了8个bytepool->elements = kmalloc_node(min_nr * sizeof(void *),      gfp_mask, node_id);if (!pool->elements) {kfree(pool);return NULL;}spin_lock_init(&pool->lock);pool->min_nr = min_nr;pool->pool_data = pool_data;init_waitqueue_head(&pool->wait);pool->alloc = alloc_fn;pool->free = free_fn;/* * First pre-allocate the guaranteed number of buffers. *///如果pool->curr_nr < pool->min_nr 的话,会再预留一部分 while (pool->curr_nr < pool->min_nr) {void *element;element = pool->alloc(gfp_mask, pool->pool_data);if (unlikely(!element)) {mempool_destroy(pool);return NULL;}//通过add_element 将pool 添加到list中去add_element(pool, element);}return pool;}可见在新建memory pool的时候,就会预留一定的memory,其中预留的memory是以byte为单位的。预留的内存块都是等长的,其中长度是sizeof(void *)。这里还要注意在新建memory pool的时候,还要提供两个函数指针用于申请和释放memory。这两个函数可以自己写,也可以用kernel提供的线程的。其中kernel提供的如下:/* * A commonly used alloc and free fn. */void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data){struct kmem_cache *mem = pool_data;VM_BUG_ON(mem->ctor);return kmem_cache_alloc(mem, gfp_mask);}EXPORT_SYMBOL(mempool_alloc_slab);void mempool_free_slab(void *element, void *pool_data){struct kmem_cache *mem = pool_data;kmem_cache_free(mem, element);}EXPORT_SYMBOL(mempool_free_slab);/* * A commonly used alloc and free fn that kmalloc/kfrees the amount of memory * specified by pool_data */void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data){size_t size = (size_t)pool_data;return kmalloc(size, gfp_mask);}EXPORT_SYMBOL(mempool_kmalloc);void mempool_kfree(void *element, void *pool_data){kfree(element);}EXPORT_SYMBOL(mempool_kfree);/* * A simple mempool-backed page allocator that allocates pages * of the order specified by pool_data. */void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data){int order = (int)(long)pool_data;return alloc_pages(gfp_mask, order);}EXPORT_SYMBOL(mempool_alloc_pages);void mempool_free_pages(void *element, void *pool_data){int order = (int)(long)pool_data;__free_pages(element, order);}EXPORT_SYMBOL(mempool_free_pages);新建memory pool后,如果要从memory pool中申请memory的话,需要调用mempool_allocvoid *mempool_alloc(mempool_t *pool, gfp_t gfp_mask){void *element;unsigned long flags;wait_queue_entry_t wait;gfp_t gfp_temp;VM_WARN_ON_ONCE(gfp_mask & __GFP_ZERO);might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM);gfp_mask |= __GFP_NOMEMALLOC;/* don't allocate emergency reserves */gfp_mask |= __GFP_NORETRY;/* don't loop in __alloc_pages */gfp_mask |= __GFP_NOWARN;/* failures are OK */gfp_temp = gfp_mask & ~(__GFP_DIRECT_RECLAIM|__GFP_IO);repeat_alloc://首先通过pool的alloc函数申请,假如我们在新建pool的时候,提供的pool函数是mempool_alloc_slab的话,则这里其实是从个mempool_alloc_slab 来向kernel申请memory。如果这里没有失败的话,则mempool就和普通的kmalloc 函数没啥区别。如果这里失败的话,则会向新建pool时候预留的8 byte(本例子的举例数据)来申请element = pool->alloc(gfp_temp, pool->pool_data);if (likely(element != NULL))return element;spin_lock_irqsave(&pool->lock, flags);if (likely(pool->curr_nr)) {从mempool的list中去掉一个,然后返回给调用者element = remove_element(pool, gfp_temp);spin_unlock_irqrestore(&pool->lock, flags);/* paired with rmb in mempool_free(), read comment there */smp_wmb();/* * Update the allocation stack trace as this is more useful * for debugging. */kmemleak_update_trace(element);return element;}/* * We use gfp mask w/o direct reclaim or IO for the first round.  If * alloc failed with that and @pool was empty, retry immediately. */if (gfp_temp != gfp_mask) {spin_unlock_irqrestore(&pool->lock, flags);gfp_temp = gfp_mask;goto repeat_alloc;}/* We must not sleep if !__GFP_DIRECT_RECLAIM */if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {spin_unlock_irqrestore(&pool->lock, flags);return NULL;}/* Let's wait for someone else to return an element to @pool */init_wait(&wait);prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);spin_unlock_irqrestore(&pool->lock, flags);/* * FIXME: this should be io_schedule().  The timeout is there as a * workaround for some DM problems in 2.6.18. */io_schedule_timeout(5*HZ);finish_wait(&pool->wait, &wait);goto repeat_alloc;}

原创粉丝点击