zoukankan      html  css  js  c++  java
  • mm/vmalloc.c

    /*
     *  linux/mm/vmalloc.c
     *
     *  Copyright (C) 1993  Linus Torvalds
     */

    #include <asm/system.h>
    #include <linux/config.h>

    #include <linux/signal.h>
    #include <linux/sched.h>
    #include <linux/head.h>
    #include <linux/kernel.h>
    #include <linux/errno.h>
    #include <linux/types.h>
    #include <linux/malloc.h>
    #include <asm/segment.h>

    //虚拟内存结构体定义
    struct vm_struct {
        unsigned long flags;          //标志
        void * addr;                  //地址
        unsigned long size;           //长度
        struct vm_struct * next;      //下一个指针
    };

    static struct vm_struct * vmlist = NULL;

    /* Just any arbitrary offset to the start of the vmalloc VM area: the
     * current 8MB value just means that there will be a 8MB "hole" after the
     * physical memory until the kernel virtual memory starts.  That means that
     * any out-of-bounds memory accesses will hopefully be caught.
     * The vmalloc() routines leaves a hole of 4kB between each vmalloced
     * area for the same reason. ;)
     */
    #define VMALLOC_OFFSET    (8*1024*1024)

    //设置页目录,实际上每个任务都知道其它任务的页目录
    static inline void set_pgdir(unsigned long dindex, unsigned long value)
    {
        struct task_struct * p;
        //取init任务
        p = &init_task;
        //每个任务中的指定索引设置为指定值
        do {
            ((unsigned long *) p->tss.cr3)[dindex] = value;
            p = p->next_task;
        } while (p != &init_task);
    }

    //释放区域页面
    static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
    {
        unsigned long page, *pte;
        
        //找到页表
        if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex])))
            return 0;
        //
        page &= PAGE_MASK;
        //页表中索引
        pte = index + (unsigned long *) page;
        //遍历释放内存页
        do {
            unsigned long pg = *pte;
            *pte = 0;
            if (pg & PAGE_PRESENT)
                free_page(pg);
            pte++;
        } while (--nr);
        //指向页表
        pte = (unsigned long *) page;
        //页表中
        for (nr = 0 ; nr < 1024 ; nr++, pte++)
            if (*pte)
                return 0;
        //设置页目录表项
        set_pgdir(dindex,0);
        mem_map[MAP_NR(page)] = 1;
        //释放页表所在页面
        free_page(page);
        //刷新
        invalidate();
        return 0;
    }

    //分配区域页面
    static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
    {
        unsigned long page, *pte;
        
        //根据索引从页目录中找到页表
        page = swapper_pg_dir[dindex];
        //如果页面不存在
        if (!page) {
            //从核心内存中申请一页内存
            page = get_free_page(GFP_KERNEL);
            //如果申请不到,则退出
            if (!page)
                return -ENOMEM;
            //如果能够获取到指定页面
            if (swapper_pg_dir[dindex]) {
                //则释放刚刚申请的页面
                free_page(page);
                //使用索引到的页面
                page = swapper_pg_dir[dindex];
            } else {
                //设置页面属性
                mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
                set_pgdir(dindex, page | PAGE_SHARED);
            }
        }
        //已经获取到页面了
        //页面边界对齐
        page &= PAGE_MASK;
        //指定内存
        pte = index + (unsigned long *) page;
        //从竞争中移除,设置为共享
        *pte = PAGE_SHARED;        /* remove a race with vfree() */
        //循环申请内存,共计nr页
        do {
            //申请一页内存
            unsigned long pg = get_free_page(GFP_KERNEL);
            
            //申请失败,返回错误
            if (!pg)
                return -ENOMEM;
            //申请成功,设置属性
            *pte = pg | PAGE_SHARED;
            pte++;
        } while (--nr);
        invalidate();
        return 0;
    }

    //执行
    static int do_area(void * addr, unsigned long size,
        int (*area_fn)(unsigned long,unsigned long,unsigned long))
    {
        unsigned long nr, dindex, index;
        
        //内存页数
        nr = size >> PAGE_SHIFT;
        //页目录索引
        dindex = (TASK_SIZE + (unsigned long) addr) >> 22;
        //页表索引
        index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
        //遍历处理,执行area_fn功能
        while (nr > 0) {
            unsigned long i = PTRS_PER_PAGE - index;

            if (i > nr)
                i = nr;
            nr -= i;
            if (area_fn(dindex, index, i))
                return -1;
            index = 0;
            dindex++;
        }
        return 0;
    }

    //释放虚拟内存
    void vfree(void * addr)
    {
        struct vm_struct **p, *tmp;

        if (!addr)
            return;
        if ((PAGE_SIZE-1) & (unsigned long) addr) {
            printk("Trying to vfree() bad address (%p) ", addr);
            return;
        }
        for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
            if (tmp->addr == addr) {
                *p = tmp->next;
                do_area(tmp->addr, tmp->size, free_area_pages);
                kfree(tmp);
                return;
            }
        }
        printk("Trying to vfree() nonexistent vm area (%p) ", addr);
    }

    //分配虚拟内存
    void * vmalloc(unsigned long size)
    {
        void * addr;
        struct vm_struct **p, *tmp, *area;

        size = PAGE_ALIGN(size);
        if (!size || size > high_memory)
            return NULL;
        area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
        if (!area)
            return NULL;
        addr = (void *) ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
        area->size = size + PAGE_SIZE;
        area->next = NULL;
        for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
            if (size + (unsigned long) addr < (unsigned long) tmp->addr)
                break;
            addr = (void *) (tmp->size + (unsigned long) tmp->addr);
        }
        area->addr = addr;
        area->next = *p;
        *p = area;
        if (do_area(addr, size, alloc_area_pages)) {
            vfree(addr);
            return NULL;
        }
        return addr;
    }

    //读取
    int vread(char *buf, char *addr, int count)
    {
        struct vm_struct **p, *tmp;
        char *vaddr, *buf_start = buf;
        int n;

        for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
            vaddr = (char *) tmp->addr;
            while (addr < vaddr) {
                if (count == 0)
                    goto finished;
                put_fs_byte('', buf++), addr++, count--;
            }
            n = tmp->size - PAGE_SIZE;
            if (addr > vaddr)
                n -= addr - vaddr;
            while (--n >= 0) {
                if (count == 0)
                    goto finished;
                put_fs_byte(*addr++, buf++), count--;
            }
        }
    finished:
        return buf - buf_start;
    }

  • 相关阅读:
    load data to matlab
    Apriori algorithm
    LOGIN Dialogue of Qt
    Methods for outlier detection
    MFC改变对话框背景色
    g++宏扩展
    Some key terms of Data Mining
    Qt QLabel 显示中文
    How To Debug a Pyhon Program
    C++命名规范
  • 原文地址:https://www.cnblogs.com/xiaofengwei/p/3773993.html
Copyright © 2011-2022 走看看