linux 设备驱动程序第8章

 

 Allocating memory

Kmalloc

Kmalloc 可以用来在内核中申请小块的物理地址连续内存,申请的内存里的内容不会被清零。

函数声明

#include <linux/slab.h>

void *kmalloc(size_t size, int flags);

参数说明:size是表示申请的内存大小,flags表示申请内存的方式,GFP_KERNEL的前缀GFP表示最终调用的函数是__get_free_pages.使用GFP_KERNEL意味着当前进程可能会被休眠,直到有空闲的内存页可以被申请,这就要求调用kmalloc的函数必须是可重入的,且不能有原子语句。

如果进程不能被sleep的话,就需要使用GFP_ATOMIC了。通常情况下kernel会保留一些空闲的pages以备不时之需,如果使用GFP_ATOMIC,那么即使kernel中只有一页空闲的内存,也能申请成功。当然一页都没有的话,就会失败了。

内存区一般分为三种,分别是NORMALDMA_zoneHIGH_zone.如果要求分配dma传输空间的话,只会考虑DMA_zone的内存。三种内存区的分类依赖于硬件,对于大部分arm架构来说,所有内存都是DMA_zone的。

Kmalloc申请的最小内存区为3264字节,最大的值也有限制,一般是128k字节。

后备高速缓存(lookaside cache)

一些设备驱动中可能会反复分配和释放同样大小的内存块,这时就可以将这些内存块放在缓存上。在linux 2.6USBSCSI驱动程序就使用了这种高速的缓存。

使用方法,步骤一,创建一个高速缓存对象,函数:

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));

参数size表示将来申请的内存块的大小,两个函数是可选参数,在对象创建和释放的时候调用。

步骤二,继续申请内存块

   void *kmem_cache_alloc(kmem_cache_t *cache, int flags);

参数cache就是刚申请的高速缓存。

步骤三、用完了就释放

void kmem_cache_free(kmem_cache_t *cache, const void *obj);

步骤四、所有内存块都用完了,释放高速缓存

int kmem_cache_destroy(kmem_cache_t *cache);

内存池(Memory Pools)

内核中有些地方的内存分配是不允许失败的。为了在这种情况下,内存分配成功,内核开发者提供了一种名为内存池(mempool)的对象。它试图始终保持一定数量的空闲内存,以便在紧急状态下使用。

内存池对象的类型是mempool_t创建方法是

 mempool_t *mempool_create(int min_nr,

                              mempool_alloc_t *alloc_fn,

                              mempool_free_t *free_fn,

                              void *pool_data);

参数min_nr表示保持的对象的最小分配数目。对象的实际分配和释放函数由alloc_fnfree_fn处理。原型如下:

typedef void *(mempool_alloc_t)(int gfp_mask, void *pool_data);

typedef void (mempool_free_t)(void *element, void *pool_data);

最后一个参数pool_data,将被传入alloc_fnfree_fn

内核中提供了这两个函数,分别是mempool_alloc_slab 和 mempool_free_slab。它们会调用kmem_cache_alloc kmem_cache_free。所以构造内存池的代码一般如下,步骤一:申请后备缓存和内存池

               cache = kmem_cache_create(. . .);

               pool = mempool_create(MY_POOL_MINIMUM,

                        mempool_alloc_slab, mempool_free_slab,cache);

步骤二:分配和释放对象

void *mempool_alloc(mempool_t *pool, int gfp_mask);

void mempool_free(void *element, mempool_t *pool);

mempool_alloc先通过普通分配函数进行分配,如果分配失败,就使用mem_pool里事先申请的内存。mempool_free释放一个对象时,如果内存池中的对象数目低于最低值,就将对象保存到内存池中,否则这个对象才还给系统。

也可以调整mempool的大小:

int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);

步骤三:删除内存池

void mempool_destroy(mempool_t *pool);

切记删除之前,必须将所有分配的对象返回内存池,否则会出现oops错误。

由于mem_pool会造成大量的内存浪费,因此一般不要使用。

Get_free_page及其相关函数

如果驱动中需要分配大块的内存,这时使用面向页的分配技术会更好一些。分配页面的函数如下:

(1)get_zeroed_page(unsigned int flags);

      返回指向新页面的指针,并将页面清零

(2)__get_free_page(unsigned int flags);

      返回指向新页面的指针,不清零

(3)__get_free_pages(unsigned int flags, unsigned int order);

     分配物理地址连续的若干页面,并返回指向第一个字节的指针。不清零

Order表示页面数量为2order次幂,比如order = 0,即一个页面,order = 3,即8个页面。允许的order的最大值一般是10或者11(对应1024或者2048个页),这依赖于体系结构。

删除函数:

void free_page(unsigned long addr);

void free_pages(unsigned long addr, unsigned long order);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值