Linux 进程地址空间1_数据结构和接口

来源:互联网 发布:手机一键装windows系统 编辑:程序博客网 时间:2024/05/15 23:48

数据结构

内存描述符:

mm_struct<linux/sched.h>

struct mm_struct {

    struct vm_area_struct * mmap;          /*内存区域链表*/

    rb_root_t mm_rb;                       /*内存区域红黑树的根*/

    struct vm_area_struct * mmap_cache;    /*最后使用的内存区域*/

    pgd_t * pgd;                /*页全局目录*/

    atomic_t mm_users;          /*正在使用该地址的进程数*/

    atomic_t mm_count;          /*主引用计数*/

    int map_count;              /*内存区域数目*/

    struct rw_semaphore mmap_sem;      /*内存区域信号量*/

    spinlock_t page_table_lock;     /*页表锁*/

    struct list_head mmlist;        /*包含全部mm_struct的链表*/

 

    unsigned long start_code, end_code, start_data, end_data;

    /*代码段的开始地址、结束地址;数据段的首地址、尾地址*/

 

    unsigned long start_brk, brk, start_stack;

    /*堆的首地址、尾地址,进程栈的首地址*/

 

    unsigned long arg_start, arg_end, env_start, env_end;

    /*命令行参数的首地址、尾地址;环境变量的首地址、尾地址*/

 

    unsigned long rss, total_vm, locked_vm;

    /*物理页,全部页面数目,上锁的页面数目*/

 

    unsigned long def_flags;    /*默认的访问标志*/

    unsigned long cpu_vm_mask;      /*lazy TLB交换掩码*/

    unsigned long swap_address; /*最后被扫描的地址*/

 

    unsigned dumpable:1;        /*是否可以产生内存信息转储*/

 

    /* Architecture-specific MM context */

    mm_context_t context;           /*体系结构特殊数据*/

};

对数据的一些解释:

    mm_users记录的是那些需要访问该内存空间的进程数 mm_count 记录的是那些和该内存空间相关的匿名进程数。匿名进程是指:该进程只是借用该mm_struct,但不会访问该内存空间的进程,mm_count被第一个访问它的进程初始化为1.

    mmapmm_rb这两个不同数据结构体描述的对象是相同的。

    在进程的进程描述符中,mm域存放着该进程使用的内存描述符,所以current->mm便指向当前进程的内存描述符。

mm_struct与内核线程:

       内核线程没有进程地址空间,也没有相关的内存描述符。所以内核线程对应的进程描述符中mm域为空,即:他们没有用户上下文。当新内核线程运行时,内核线程将直接使用前一个进程的内存描述符。

内存区域

       内存区域由vm_area_struct<linux/mm.h>结构体描述,内存区域在内核中经常被称作虚拟内存区域VMAvm_area_struct用于描述指定地址空间内连续区间上的一个独立内存范围。内核将每个内存区域作为一个单独的内存对象管理,每个内存区域都拥有一致的属性。

struct vm_area_struct {

    struct mm_struct * vm_mm;   /*mm_struct所属的VMA结构*/

    unsigned long vm_start;     /*区间的首地址*/

    unsigned long vm_end;       /*区间的尾地址*/

 

    struct vm_area_struct *vm_next;    /*VMA链表*/

    pgprot_t vm_page_prot;      /*访问控制权限*/

    unsigned long vm_flags;     /*标志*/

    rb_node_t vm_rb;            /*??该VMA节点所属的红黑树的根*/

 

    /*

     * For areas with an address space and backing store,

     * one of the address_space->i_mmap{,shared} lists,

     * for shm areas, the list of attaches, otherwise unused.

     */

    struct vm_area_struct *vm_next_share;

    struct vm_area_struct **vm_pprev_share;

 

    /* Function pointers to deal with this struct. */

    struct vm_operations_struct * vm_ops;     /*操作表*/

 

    /* Information about our backing store: */

    unsigned long vm_pgoff;     /*文件中的偏离量*/

    struct file * vm_file;      /*被映射的文件(can be NULL). */

    unsigned long vm_raend;     /* XXX: put full readahead info here. */

    void * vm_private_data;     /* was vm_pte (shared mem) 私有数据*/

};

vm_mm域指向和VMA相关的mm_struct结构体,每个VMA对其相关的mm_struct结构体来说都是唯一的,及时两个独立的进程将同一个文件映射到各自的地址空间,他们分别会有一个vm_area_struct结构体来标志自己的内存区域(两个线程共享一个地址空间除外)。

相关接口

vm_area_struct结构体中的vm_ops域指向与该区域相关的操作函数表,内核使用表中的方法操作VMAvm_area_struct作为通用对象代表了任何类型的内存域,而操作表描述针对特定的对象实例的特定方法。

vm_operations_struct<linux/mm.h>

struct vm_operations_struct {

    void (*open)(struct vm_area_struct * area);

    /*指定的内存区域被加入到一个地址空间时,该函数被调用*/

 

    void (*close)(struct vm_area_struct * area);

    /*制定的内存区域从地址空间删除时,该函数被调用*/

 

    struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused);

    /*要访问的页面不再物理内存中时,该函数被页面错误处理程序调用*/

};

 

查找地址区间:

<mm/mmap.c>

struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)

/*在制定的地址空间中搜索第一个vm_end大于addr的内存区域*/

 

<linux/mm.h>

struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,struct vm_area_struct **pprev) /*返回第一个小于addrVMA*/

 

<linux/mm.h>

static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)

/*返回第一个和指定地址区间相交的VMA*/

 

 

创建地址区间

内核中的两种内存映射的函数:

<linux/mm.h>

static inline unsigned long do_mmap(

struct file *file, unsigned long addr,

    unsigned long len, unsigned long prot,

    unsigned long flag, unsigned long offset)

/*映射由file制定的文件,具体映射的是文件中从偏移offset出开始,长度为len字节的范围内的数据。成功的话,它会在虚拟内存中分配一个合适的新内存区域,如果有可能的话,将新区域和邻近区域合并,否则内核从vm_area_cachep(slab)缓存中分配一个vm_area_struct结构体,并更新红黑树和链表*/

 

<Sys_i386.c>

static inline long do_mmap2(

    unsigned long addr, unsigned long len,

    unsigned long prot, unsigned long flags,

    unsigned long fd, unsigned long pgoff)

/*do_mmap的变种,作用也是内存空间映射,最后一个参数pgoff是页面偏移,能够偏移更大的位置*/

 

用户空间可以通过mmap()系统调用获取内核函数do_mmap()的功能。

 

删除地址空间

<linux/mm.h>

int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)

/*从特定的进程地址空间中删除指定地址空间。mm指定要删除区域所在的地址空间,删除从地址start开始,长度为len字节的地址区间,返回零表示成功。*/

 

<linux/mm/mmap.c>

int munmap(void *start, size_t length)

/*给用户空间提供的从自身地址空间中删除指定地址去见的方法,是对do_munmap()的简单封装*/

原创粉丝点击