/*
 *  linux/mm/kmalloc.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds & Roger Wolff.
 *
 *  Written by R.E. Wolff Sept/Oct '93.
 *
 */

#include <linux/mm.h>
#include <asm/system.h>
#include <linux/delay.h>

#define GFP_LEVEL_MASK 0xf

/* I want this low enough for a while to catch errors.
   I want this number to be increased in the near future:
        loadable device drivers should use this function to get memory */

//最大分配的数量4k
#define MAX_KMALLOC_K 4

/* This defines how many times we should try to allocate a free page before
   giving up. Normally this shouldn't happen at all. */
   //获取空闲页尝试次数 4
#define MAX_GET_FREE_PAGE_TRIES 4

/* Private flags. */

#define MF_USED 0xffaa0055
#define MF_FREE 0x0055ffaa

/*
 * Much care has gone into making these routines in this file reentrant.
 *
 * The fancy bookkeeping of nbytesmalloced and the like are only used to
 * report them to the user (oooohhhhh, aaaaahhhhh....) are not
 * protected by cli(). (If that goes wrong. So what?)
 *
 * These routines restore the interrupt status to allow calling with ints
 * off.
 */

/*
 * A block header. This is in front of every malloc-block, whether free or not.
 */
 //block首部结构体,此结构体在malloc-block前端
struct block_header {
    unsigned long bh_flags;                  //block首部标志
    union {                                  
        unsigned long ubh_length;            //block长度
        struct block_header *fbh_next;       //下一个block长度
    } vp;
};

#define bh_length vp.ubh_length                   //长度
#define bh_next   vp.fbh_next                     //下一个指针
#define BH(p) ((struct block_header *)(p))        //转化为block头部结构体

/*
 * The page descriptor is at the front of every page that malloc has in use.
 */
 //页描述符在每一页内存前
struct page_descriptor {
    struct page_descriptor *next;               //下一个页描述符指针
    struct block_header *firstfree;             //block头
    int order;                                  //序号
    int nfree;                                  //空闲数量
};

//将指定位置转为页描述符结构
#define PAGE_DESC(p) ((struct page_descriptor *)(((unsigned long)(p)) & PAGE_MASK))

/*
 * A size descriptor describes a specific class of malloc sizes.
 * Each class of sizes has its own freelist.
 */
 //长度描述符
struct size_descriptor {
    struct page_descriptor *firstfree;    //页描述符指针
    int size;                             //大小
    int nblocks;                          //block数量

int nmallocs;                        //分配数量
    int nfrees;                          //释放数量
    int nbytesmalloced;                  //按位分配
    int npages;                          //页数量
};

//描述符数组
struct size_descriptor sizes[] = {
    { NULL,  32,127, 0,0,0,0 },
    { NULL,  64, 63, 0,0,0,0 },
    { NULL, 128, 31, 0,0,0,0 },
    { NULL, 252, 16, 0,0,0,0 },
    { NULL, 508,  8, 0,0,0,0 },
    { NULL,1020,  4, 0,0,0,0 },
    { NULL,2040,  2, 0,0,0,0 },
    { NULL,4080,  1, 0,0,0,0 },
    { NULL,   0,  0, 0,0,0,0 }
};

#define NBLOCKS(order)          (sizes[order].nblocks)
#define BLOCKSIZE(order)        (sizes[order].size)

//初始化
long kmalloc_init (long start_mem,long end_mem)
{
    int order;

/*
 * Check the static info array. Things will blow up terribly if it's
 * incorrect. This is a late "compile time" check.....
 */
 //检测静态信息数组,如果这里发生错误,后续爆发会很可怕
    for (order = 0;BLOCKSIZE(order);order++)
    {
        //校验静态数组所分配的空间是否大于一页内存 size * 块数 + 描述符大小
        if ((NBLOCKS (order)*BLOCKSIZE(order) + sizeof (struct page_descriptor)) >
            PAGE_SIZE)
        {
            printk ("Cannot use %d bytes out of %d in order = %d block mallocs\n",
                NBLOCKS (order) * BLOCKSIZE(order) +
                        sizeof (struct page_descriptor),
                (int) PAGE_SIZE,
                BLOCKSIZE (order));
            panic ("This only happens if someone messes with kmalloc");
        }
    }
    return start_mem;
}

//根据大小获取序号
int get_order (int size)
{
    int order;

/* Add the size of the header */
    size += sizeof (struct block_header);
    for (order = 0;BLOCKSIZE(order);order++)
        if (size <= BLOCKSIZE (order))
            return order;
    return -1;
}

//分配内存
void * kmalloc (size_t size, int priority)
{
    unsigned long flags;
    int order,tries,i,sz;
    struct block_header *p;
    struct page_descriptor *page;
    extern unsigned long intr_count;

/* Sanity check... */
//校验
    if (intr_count && priority != GFP_ATOMIC) {
        printk("kmalloc called nonatomically from interrupt %08lx\n",
            ((unsigned long *)&size)[-1]);
        priority = GFP_ATOMIC;
    }
    //如果分配的空间大于4k
if (size > MAX_KMALLOC_K * 1024)
     {
         //输出相关信息,拒绝分配过大空间
     printk ("kmalloc: I refuse to allocate %d bytes (for now max = %d).\n",
                size,MAX_KMALLOC_K*1024);
     return (NULL);
     }
//根据需要分配的空间获取序号
order = get_order (size);
if (order < 0)
    {
    printk ("kmalloc of too large a block (%d bytes).\n",size);
    return (NULL);
    }
//保存标志寄存器
save_flags(flags);

/* It seems VERY unlikely to me that it would be possible that this
   loop will get executed more than once. */
   //希望只执行一次
tries = MAX_GET_FREE_PAGE_TRIES;
while (tries --)
    {
    /* Try to allocate a "recently" freed memory block */
    //尽可能分配最近的空闲内存块
    cli ();
    //
    if ((page = sizes[order].firstfree) &&                  //页描述符指针不空并且页面的block头不空
        (p    =  page->firstfree))
        {
            //内存块头中的标志为空闲
        if (p->bh_flags == MF_FREE)
            {
                //页描述符中第一个空闲位置为下一个内存块头
            page->firstfree = p->bh_next;
            //当前页所能分配的数量减少一个
            page->nfree--;
            //如果剩余分配数量为0
            if (!page->nfree)
                {
                    //则当前数组指向下一页,以待下次分配
                sizes[order].firstfree = page->next;
                page->next = NULL;
                }
            restore_flags(flags);
            //设置相关参数
            sizes [order].nmallocs++;
            sizes [order].nbytesmalloced += size;
            p->bh_flags =  MF_USED; /* As of now this block is officially in use */
            p->bh_length = size;
            //这里完成分配返回
            return p+1; /* Pointer arithmetic: increments past header */            
            }
        //此时内存块在空闲链表中,但是指针p的位置不空闲,返回空值,分配失败
        printk ("Problem: block on freelist at %08lx isn't free.\n",(long)p);
        return (NULL);
        }
    //恢复标志寄存器
    restore_flags(flags);

/* Now we're in trouble: We need to get a new free page..... */
    //现在我们有麻烦了,我们需要获取一个新的空闲页
    //根据order确定sz
    sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */

/* This can be done with ints on: This is private to this invocation */
    //申请一页内存,取内存页前面的页描述符
    page = (struct page_descriptor *) __get_free_page (priority & GFP_LEVEL_MASK);
    //如果获取的描述符为空,则申请失败
    if (!page)
        {
        printk ("Couldn't get a free page.....\n");
        return NULL;
        }
#if 0
    printk ("Got page %08x to use for %d byte mallocs....",(long)page,sz);
#endif
    //申请内存页成功,则此类型页面增加一页
    sizes[order].npages++;

/* Loop for all but last block: */
    //循环初始化内存块
    for (i=NBLOCKS(order),p=BH (page+1);i > 1;i--,p=p->bh_next)
        {
        p->bh_flags = MF_FREE;
        p->bh_next = BH ( ((long)p)+sz);
        }
    /* Last block: */
    //初始化最后一个内存块
    p->bh_flags = MF_FREE;
    p->bh_next = NULL;
    //初始化页描述符
    page->order = order;
    page->nfree = NBLOCKS(order);
    page->firstfree = BH(page+1);
#if 0
    printk ("%d blocks per page\n",page->nfree);
#endif
    /* Now we're going to muck with the "global" freelist for this size:
       this should be uniterruptible */
    cli ();
    /*
     * sizes[order].firstfree used to be NULL, otherwise we wouldn't be
     * here, but you never know....
     */
    page->next = sizes[order].firstfree;
    sizes[order].firstfree = page;
    restore_flags(flags);
    }

/* Pray that printk won't cause this to happen again :-) */
//分配失败的提示

printk ("Hey. This is very funny. I tried %d times to allocate a whole\n"
        "new page for an object only %d bytes long, but some other process\n"
        "beat me to actually allocating it. Also note that this 'error'\n"
        "message is soooo very long to catch your attention. I'd appreciate\n"
        "it if you'd be so kind as to report what conditions caused this to\n"
        "the author of this kmalloc: wolff@dutecai.et.tudelft.nl.\n"
        "(Executive summary: This can't happen)\n",
                MAX_GET_FREE_PAGE_TRIES,
                size);
return NULL;
}

//释放
void kfree_s (void *ptr,int size)
{
    //标志
unsigned long flags;
//顺序
int order;
//内存块头指针
register struct block_header *p=((struct block_header *)ptr) -1;
//页描述符指针
struct page_descriptor *page,*pg2;

//根据参数获取内存块头部,根据头部获取内存页的页描述符
page = PAGE_DESC (p);
//根据页描述符指针获取到order
order = page->order;
if ((order < 0) ||
    (order > sizeof (sizes)/sizeof (sizes[0])) ||
    (((long)(page->next)) & ~PAGE_MASK) ||
    (p->bh_flags != MF_USED))
    {
    printk ("kfree of non-kmalloced memory: %p, next= %p, order=%d\n",
                p, page->next, page->order);
    return;
    }
    //
if (size &&
    size != p->bh_length)
    {
    printk ("Trying to free pointer at %p with wrong size: %d instead of %lu.\n",
        p,size,p->bh_length);
    return;
    }
    //获取内存块的大小
size = p->bh_length;
//释放
p->bh_flags = MF_FREE; /* As of now this block is officially free */

save_flags(flags);
cli ();
//初始化相关参数
p->bh_next = page->firstfree;
page->firstfree = p;
page->nfree ++;

if (page->nfree == 1)
   { /* Page went from full to one free block: put it on the freelist */
   if (page->next)
        {
        printk ("Page %p already on freelist dazed and confused....\n", page);
        }
   else
        {
        page->next = sizes[order].firstfree;
        sizes[order].firstfree = page;
        }
   }

/* If page is completely free, free it */
//内存页完全空闲的处理,实际上就是释放此内存页面
if (page->nfree == NBLOCKS (page->order))
    {
#if 0
    printk ("Freeing page %08x.\n", (long)page);
#endif
    if (sizes[order].firstfree == page)
        {
        sizes[order].firstfree = page->next;
        }
    else
        {
        for (pg2=sizes[order].firstfree;
                (pg2 != NULL) && (pg2->next != page);
                        pg2=pg2->next)
            /* Nothing */;
        if (pg2 != NULL)
            pg2->next = page->next;
        else
            printk ("Ooops. page %p doesn't show on freelist.\n", page);
        }
    free_page ((long)page);
    }
restore_flags(flags);

//正常处理
sizes[order].nfrees++;      /* Noncritical (monitoring) admin stuff */
sizes[order].nbytesmalloced -= size;
}

mm/kmalloc.c的更多相关文章

  1. (linux)main.c中的初始化

    main.c中的初始化 head.s在最后部分调用main.c中的start_kernel() 函数,从而把控制权交给了它. 所以启动程序从start_kernel()函数继续执行.这个函数是main ...

  2. 《ucore lab5》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1: 加载应用程序并执行(需要编码) 题目 do_execv函数调用load_icode(位于kern/process/proc.c中) 来 ...

  3. mm/vmalloc.c

    /* *  linux/mm/vmalloc.c * *  Copyright (C) 1993  Linus Torvalds */ #include <asm/system.h>#in ...

  4. mm/mmap.c

    /* *    linux/mm/mmap.c * * Written by obz. */#include <linux/stat.h>#include <linux/sched. ...

  5. mm/makefile

    ## Makefile for the linux memory manager.## Note! Dependencies are done automagically by 'make dep', ...

  6. Memory Allocation API In Linux Kernel && Linux Userspace、kmalloc vmalloc Difference、Kernel Large Section Memory Allocation

    目录 . 内核态(ring0)内存申请和用户态(ring3)内存申请 . 内核态(ring0)内存申请:kmalloc/kfree.vmalloc/vfree . 用户态(ring3)内存申请:mal ...

  7. kmalloc/kfree,vmalloc/vfree函数用法和区别

    http://blog.csdn.net/tigerjibo/article/details/6412881 kmalloc/kfree,vmalloc/vfree函数用法和区别 1.kmalloc ...

  8. kmalloc分配物理内存与高端内存映射--Linux内存管理(十八)

    1 前景回顾 1.1 内核映射区 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供 ...

  9. swapper_pg_dir主内核页表、init和kthreadd、do_fork时新建子进程页表、vmalloc与kmalloc

    都是以前看到一个点扯出的很多东西,当时做的总结,有问题欢迎讨论,现在来源难寻,侵删! 1.Init_task.idle.init和kthreadd的区别和联系 idle进程其pid=0,其前身是系统创 ...

随机推荐

  1. Sprint(第三天11.16)

    Sprint1第一阶段 1.类名:软件工程-第一阶段 2.时间:11.14-11.23 3.选题内容:点餐系统 4.团队博客地址:http://www.cnblogs.com/iamCarson/ 团 ...

  2. HDU-4526 威威猫系列故事——拼车记 动态规划

    分析:该题有2个地方要注意:所有的车要么不坐要么就坐满,这个贪心策略很容易证明是正确的,还有一点就是最后一辆车除外. #include <cstdlib> #include <cst ...

  3. (八)open函数的flag详解

    3.1.4.open函数的flag详解13.1.4.1.读写权限:O_RDONLY O_WRONLY O_RDWR(1)linux中文件有读写权限,我们在open打开文件时也可以附带一定的权限说明(譬 ...

  4. 查看rpm和war包内容

    解压rpm包的内容:(没有安装,就像解压tgz包一样rpm包)rpm2cpio *.rpm | cpio -div 解压war包的内容: jar -xvf project.war 解压到当前目录

  5. Python3.X新特性之print和exec

    print print 现在是一个函数,不再是一个语句.<语法更为清晰> 实例1 打开文件 log.txt 以便进行写入并将对象指定给 fid.然后利用 print将一个字符串重定向给文件 ...

  6. eclipse中配置tomcat后,运行jsp时出现Server Tomcat v7.0 Server at localhost failed to start.

    最近在进行jsp开发学习,在配置上还是遇到很多问题. 在连接好数据库后,写了第一个jsp测试页面,结果在运行eclipse中运行toamcat时出现了错误提示:Server Tomcat v7.0 S ...

  7. 51nod 1445 变色DNA(dij)

    题目链接:51nod 1445 变色DNA 看了相关讨论再去用最短路:val[i][j]之间如果是'Y',说明i可以到达j,并且i到达j的代价是i那行 1到j-1 里面'Y'的数量. 最后,求 0到n ...

  8. C#窗体 WinForm 进程,线程

    一.进程 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动. 它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体. Process 类,用来操作进程. 命名空间:using Sys ...

  9. linux 的 磁盘操作

    //显示目录和文件 以kb m g为单位 du -ah //总大小 du -sh /etc //查看分区 fdisk -l //对磁盘进行分区 fdisk /dev/sdb //格式化分区 mkfs ...

  10. java中的传值与传引用

    java函数中的传值和传引用问题一直是个比较“邪门”的问题,其实java函数中的参数都是传递值的,所不同的是对于基本数据类型传递的是参数的一份拷贝,对于类类型传递的是该类参数的引用的拷贝,当在函数体中 ...