mm_struct

来源:互联网 发布:淘宝充值店没有人买 编辑:程序博客网 时间:2024/04/30 03:58
          

        一个进程的虚拟地址空间主要由两个数据结来描述。一个是最高层次的:mm_struct,一个是较高层次的:vm_area_structs。最高层次的mm_struct结构描述了一个进程的整个虚拟地址空间。较高层次的结构vm_area_truct描述了虚拟地址空间的一个区间(简称虚拟区)。每个进程只有一个mm_struct结构,在每个进程的task_struct结构中,有一个指向该进程的结构。可以说,mm_struct结构是对整个用户空间的描述。

         进程的task_stuct的一个指针指向了mm_struct,详细参考:http://blog.csdn.net/u010064842/article/details/9249665

   mm_strcut 用来描述一个进程的虚拟地址空间,在/include/linux/sched.h 中描述如下:

struct mm_struct {

  struct vm_area_struct * mmap; /* 指向虚拟区间(VMA)链表 */

  rb_root_t mm_rb; /*指向red_black树*/

  struct vm_area_struct * mmap_cache; /* 指向最近找到的虚拟区间*/

  pgd_t * pgd; /*指向进程的页目录*/ 

  atomic_t mm_users; /* 用户空间中的有多少用户*/

  atomic_t mm_count; /* 对"struct mm_struct"有多少引用*/

  int map_count; /* 虚拟区间的个数*/

  struct rw_semaphore mmap_sem;

  spinlock_t page_table_lock; /* 保护任务页表和 mm->rss */

  struct list_head mmlist; /*所有活动(active)mm的链表 */

  unsigned long start_code, end_code, start_data, end_data; /*start_code 代码段起始地址,end_code 代码段结束地址,start_data 数据段起始地址, start_end 数据段结束地址*/

  unsigned long start_brk, brk, start_stack; /*start_brk 和brk记录有关堆的信息, start_brk是用户虚拟地址空间初始化时,堆的结束地址, brk 是当前堆的结束地址, start_stack 是栈的起始地址*/

  unsigned long arg_start, arg_end, env_start, env_end; /*arg_start 参数段的起始地址, arg_end 参数段的结束地址, env_start 环境段的起始地址, env_end 环境段的结束地址*/

  unsigned long rss, total_vm, locked_vm;

  unsigned long def_flags;

  unsigned long cpu_vm_mask;

  unsigned long swap_address;

  unsigned dumpable:1;

  mm_context_t context; /* Architecture-specific MM context, 是与平台相关的一个结构,对i386 几乎用处不大*/
};


       mm_users记录了正在使用该地址的进程数目(比如有两个进程在使用,那就为2)。

       mm_count是该结构的主引用计数,只要mm_users不为0,它就为1。但其为0时,后者就为0。这时也就说明再也没有指向该mm_struct结构体的引用了,这时该结构体会被销毁。内核之所以同时使用这两个计数器是为了区别主使用计数器和使用该地址空间的进程的数目。

       mmap和mm_rb描述的都是同一个对象:该地址空间中的全部内存区域。不同只是前者以链表,后者以红黑树的形式组织。所有的mm_struct结构体都通过自身的mmlist域连接在一个双向链表中,该链表的首元素是init_mm内存描述符,它代表init进程的地址空间。另外需要注意,操作该链表的时候需要使用mmlist_lock锁来防止并发访问,该锁定义在文件kernel/fork.c中。内存描述符的总数在mmlist_nr全局变量中,该变量也定义在文件fork.c中。

      我前边说过的进程描述符中有一个mm域,这里边存放的就是该进程使用的内存描述符,通过current->mm便可以指向当前进程的内存描述符。fork函数利用copy_mm()函数就实现了复制父进程的内存描述符,而子进程中的mm_struct结构体实际是通过文件kernel/fork.c中的allocate_mm()宏从mm_cachep slab缓存中分配得到的。通常,每个进程都有唯一的mm_struct结构体。

      最后,当进程退出的时候,内核调用exit_mm()函数,这个函数调用mmput()来减少内存描述符中的mm_users用户计数。如果计数降为0,继续调用mmdrop函数,减少mm_count使用计数。如果使用计数也为0,则调用free_mm()宏通过kmem_cache_free()函数将mm_struct结构体归还到mm_cachep slab缓存中。


 
原创粉丝点击