当前所在位置:珠峰网资料 >> 计算机 >> 计算机等级考试 >> 正文
like-linux系统链表原理简单分析
发布时间:2011/1/16 17:49:46 来源:城市学习网 编辑:ziteng
 1 /*

  2  like-linux系统下链表结构分析

  3  *在like-linux系统中,链表的可移植性比较好,并不像在大学学到的链表结构那样的死板。其原理在很多linux的讲解中都有描述。

  4  *原理部分可以看一下李先静老师写的《系统程序员成长之路》一书。

  5  *本文根据xenarm中的链表来具体得理一下在like-linux系统中的链表原理。

  6

  7  *因为时间有限,只是把相关宏定义简单扩展,并把代码做了注释和筛捡。没有成文,望各位看官见谅

  8  */

  9

  10

  11 /*

  12  *定义了一个相关结构和spinlock

  13  */

  14 spinlock_t consistent_lock;

  15 struct arm_vm_region {

  16         struct list_head        vm_list;

  17         unsigned long           vm_start;

  18         unsigned long           vm_end;

  19         struct page             *vm_pages;

  20         int                     vm_active;

  21 };

  22

  23 /*

  24  *初始化一个链表头

  25  *链表头不同于链表节点,在实际分配中,链表头存放的是边界范围等一些概括信息

  26  *

  27  */

  28 static struct arm_vm_region consistent_head = {//初始化一个链表头

  29         .vm_list        = LIST_HEAD_INIT(consistent_head.vm_list),

  30         .vm_start       = CONSISTENT_BASE,

  31         .vm_end         = CONSISTENT_END,

  32 };

  33

  34 static struct arm_vm_region * arm_vm_region_alloc(struct arm_vm_region *head, size_t size, gfp_t gfp)

  35 {

  36         //head头放的是区间总体范围

  37         unsigned long addr = head->vm_start, end = head->vm_end – size;

  38         unsigned long flags;

  39         struct arm_vm_region *c, *new;

  40

  41         new = xmalloc(struct arm_vm_region);

  42         if (!new)

  43                 goto out;

  44

  45         spin_lock_irqsave(&consistent_lock, flags);

  46

  47         /*

  48            *遍历一下链表的各个节点,寻找合适的区间范围

  49            *list_for_each_entry宏是一个关键,其实是一个for循环,只不过设计的比较巧妙,依靠了链表的结构

  50            *其具体定义在下面

  51          */

  52         list_for_each_entry(c, &head->vm_list, vm_list) {

  53                 if ((addr + size) < addr)//越界

  54                         goto nospc;

  55                 if ((addr + size) <= c->vm_start)//可以夹到vm_region块之间

  56                         goto found;

  57                 addr = c->vm_end;//addr 为下一个的结束地址

  58                 if (addr > end)

  59                         goto nospc;

  60         }

  61

  62  found:

  63         /*

  64          * Insert this entry _before_ the one we found.

  65          */

  66         list_add_tail(&new->vm_list, &c->vm_list);

  67         new->vm_start = addr;

  68         new->vm_end = addr + size;

  69         new->vm_active = 1;

  70

  71         spin_unlock_irqrestore(&consistent_lock, flags);

  72         return new;

  73

  74  nospc:

  75         spin_unlock_irqrestore(&consistent_lock, flags);

  76         xfree(new);

  77  out:

  78         return NULL;

  79 }

  80

  81 /**

  82  * list_for_each_entry  -       iterate over list of given type

  83  * @pos:        the type * to use as a loop counter.

  84  * @head:       the head for your list.

  85  * @member:     the name of the list_struct within the struct.

  86  */

  87 #define list_for_each_entry(pos, head, member)                          \

  88         for (pos = list_entry((head)->next, typeof(*pos), member);      \

  89              &pos->member != (head);                                    \

  90              pos = list_entry(pos->member.next, typeof(*pos), member))

  91

  92 /**

  93  * list_entry – get the struct for this entry

  94  * @ptr:        the &struct list_head pointer.

  95  * @type:       the type of the struct this is embedded in.

  96  * @member:     the name of the list_struct within the struct.

  97  */

  98 #define list_entry(ptr, type, member) \

  99         ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

  100 [NextPage]

  101 /*

  102    **************************************************

  103  */

  104 static void * __dma_alloc(/*struct device *dev,*/size_t size, dma_addr_t *handle/*, gfp_t gfp*/,pgprot_t prot)

  105 {

  106         struct page_info *page;

  107         struct arm_vm_region *c;

  108         unsigned long order;

  109         unsigned long flags;

  110

  111         //若没有初始化,就…

  112         if (!consistent_pte[0]) {

  113                 printk(KERN_ERR "%s: not initialised\n", __func__);

  114                 return NULL;

  115         }

  116         size = round_pgup(size);

  117

  118         //若分配的空间太大了,超过了,那么就…

  119         if (

  120             size >= (CONSISTENT_END – CONSISTENT_BASE)) {

  121                 printk(KERN_WARNING "coherent allocation too big "

  122                        "(requested %#x)\n", size);

  123                 goto no_page;

  124         }

  125

  126         //转换为伙伴算法的尺寸

  127         order = get_order_from_bytes(size);

  128

  129         local_irq_save(flags);

  130         page = alloc_heap_pages(0, order);//分配的是实际的页

  131         local_irq_restore(flags);

  132         if (!page)

  133                 goto no_page;

  134

  135         c = arm_vm_region_alloc(&consistent_head, size,

  136                            /* gfp &*/ ~(__GFP_DMA | __GFP_HIGHMEM));//分配的是页框

  137         if (c) {

  138                 pte_t *pte;

  139                 struct page_info *end = page + (1 << order);

  140                 int idx = CONSISTENT_PTE_INDEX(c->vm_start);

  141                 u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);

  142

  143                 pte = consistent_pte[idx] + off;

  144                 c->vm_pages = page;

  145

  146                 *handle = page_to_phys(page);//page_to_dma(/*dev,*/ page);

  147

  148                 do {

  149                         *pte = l1e_from_paddr(page_to_phys(page), prot);//mk_pte(page, prot);

  150

  151                         page++;

  152                         pte++;

  153                         off++;

  154                         if (off >= PTRS_PER_PTE) {

  155                                 off = 0;

  156                                 cpu_flush_cache_page((unsigned long)consistent_pte[idx]);

  157                                 pte = consistent_pte[++idx];

  158                         }

  159                 } while (size -= PAGE_SIZE);

  160                 cpu_flush_cache_page((unsigned long)consistent_pte[idx]);

  161                 /*

  162                  * Free the otherwise unused pages.

  163                  */

  164                 while (page < end) {//若分配的页数没有全部被映射,于是释放掉没有被映射的页数

  165                         free_heap_pages(0/*MEMZONE_DMADOM*/,page,order);

  166                         page++;

  167                 }

  168                 return (void *)c->vm_start;

  169         }

  170         //如果没有分配vm成功的话,那么就free

  171         if (page)

  172                 free_heap_pages(0/*MEMZONE_DMADOM*/,page,order);

  173  no_page:

  174         printk("No enough memory for DMA\n");

  175         *handle = ~0;

  176         return NULL;

  177 }

  178

  179 pgprot_t pgprot_kernel;

  180 /*

  181  * Allocate a writecombining region, in much the same way as

  182  * dma_alloc_coherent above.

  183  */

  184 void *

  185 dma_alloc_writecombine(/*struct device *dev, */size_t size, dma_addr_t *handle/*, gfp_t gfp*/)

  186 {

  187         return __dma_alloc(/*dev, */size, handle, /*gfp,*/

  188                            pgprot_writecombine(pgprot_kernel));

  189 }

  190

  191 /*

  192  * Initialise the consistent memory allocation.

  193  * 先把pgd给初始化了

  194  */

  195 int consistent_init(void)

  196 {

  197         pde_t *pgd;

  198         pte_t *pte;

  199         void *pt;

  200         int ret = 0, i = 0;

  201         u32 base = CONSISTENT_BASE;

  202         pgprot_kernel = PTE_TYPE_SMALL/* | PTE_BUFFERABLE | PTE_CACHEABLE*/ | PTE_SMALL_AP_UNO_SRW;//L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | L_PTE_EXEC;

  203

  204         do {

  205                 pt = alloc_xenheap_page();//pte_alloc_kernel(pgd, base);

  206                 clear_page(pt);

  207                 idle_pg_table[pgd_index(base)] =l2e_from_page(virt_to_page(pt), PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_IO));

  208                 cpu_flush_cache_page((unsigned long) &idle_pg_table[pgd_index(base)]);

  209                 if (!pt) {

  210                         printk(KERN_ERR "%s: no pte tables\n", __func__);

  211                         ret = -ENOMEM;

  212                         break;

  213                 }

  214                 //这个数组,是为了方便以后分配dma页的时候,建立页表

  215                 consistent_pte[i++] = pt;

  216                 base += (1 << PGDIR_SHIFT);

  217         } while (base < CONSISTENT_END);

  218         printk("consistent init ok\n");

  219

  220         return ret;

  221 }

广告合作:400-664-0084 全国热线:400-664-0084
Copyright 2010 - 2017 www.my8848.com 珠峰网 粤ICP备15066211号
珠峰网 版权所有 All Rights Reserved