Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2164022
  • 博文数量: 374
  • 博客积分: 7276
  • 博客等级: 少将
  • 技术积分: 5669
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-06 16:35
文章分类

全部博文(374)

文章存档

2013年(23)

2012年(153)

2011年(198)

分类: LINUX

2012-04-09 15:17:43

内核使用内存描述符结构体表示进程的地址空间,该结构体包含了和进程地址空间有关的全部信息。内存描述符由mm_struct结构体表示,定义在文件中。进程地址空间由每个进程的线性地址区(vm_area_struct)组成。通过内核,进程可以给自己的地址空间动态的添加或减少线性区域。如下图是内存描述符mm_struct和线性区域描述符vm_area_struct的关系:

      mm_users域记录正在使用该地址的进程数目。比如,如果两个进程共享该地址空间,那么mm_users的值便等于2;mm_count域是mm_struct的结构体的主引用计数,只要mm_users不为0,那么mm_count值就等于1.当mm_users值减为0(两个线程都退出)时,mm_count域的值才变为0。如果mm_count的值等于0,说明已经没有任何指向该mm_struct结构体的引用了,这时该结构体会被销毁。mmap和mm_rb这两个不同的数据结构描述的对象是相同的:该地址空间中的全部内存区域。mmap结构体最为链表,利于简单,高效地遍历所有元素;而mm_rb结构体作为红-黑树,更适合搜索指定元素。所有的mm_struct结构体通过自身的mmlist域连接在一个双向链表中,该链表的首元素是init_mm内存描述符,它代表0号进程的地址空间。在进程的进程描述符中,mm域存放着该进程使用的内存描述符。copy_process函数利用copy_mm函数复制父进程的内存描述符。像vfork和clone系统调用指定的CLONE_VM标志的,仅仅需要在调用copy_mm()函数中将mm域指向其父进程的内存描述符就可以了:

[c-sharp] view plaincopy
  1. if(clone_flags & CLONE_VM){  
  2.     atomic_inc(&oldmm->mm_users);  
  3.     mm = oldmm;  
  4.     goto good_mm;  
  5. }  

      而fork系统调用产生的子进程中的mm_struct结构体实际是通过文件kernel/fork.c中的alloc_mm()宏从mm_cachep slab缓存中分配得到的。通常,每个进程都有一个唯一的mm_struct结构体,即唯一的进程地址空间。是否共享地址空间,几乎是进程和Linux中所谓线程间本质上的唯一区别。

      vm_start域指向线性区域的首地址,vm_end域指向尾地址之后的第一个字节,也就是说,vm_start是线性区域的开始地址,vm_end是线性区域的结束地址。vm_mm域指向和VMA相关的mm_struct结构体,注意每个VMA对其相关的mm_struct结构体来说都是唯一的,所以即使两个独立的进程将同一个文件映射到各自的地址空间,他们分别都会有一个vm_area_struct结构体来标志自己的内存区域;但是如果两个线程共享一个地址空间,那么他们也同时共享其中的所有vm_area_struct结构体。

[c-sharp] view plaincopy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. int read_myproc(char *page, char **start, off_t off, int count, int *eof, void *data){  
  8.     struct task_struct *p;  
  9.     struct vm_area_struct *first;  
  10.     p = list_entry(init_task.tasks.next, struct task_struct, tasks);  
  11.     printk("%20s %20s/n""vm_area_start""vm_area_end");  
  12.     for(first = p->mm->mmap; first != NULL;){  
  13.         printk("%20lx %20lx/n", first->vm_start, first->vm_end);  
  14.         first = first->vm->next;  
  15.     }  
  16.     return 0;  
  17. }  
  18. static int __init myproc_init(void){  
  19.     struct proc_dir_entry * e = create_proc_read_entry("myproc",0,NULL,read_myproc,NULL);  
  20.     e->read_proc = read_myproc;  
  21.     return 0;   
  22. }  
  23. static void __exit myproc_exit(void){  
  24.     removre_proc_entry("myproc",NULL);  
  25. }  
  26. module_init(myproc_init);  
  27. module_exit(myproc_exit);  
  28. MODULE_LICENSE("GPL");  
  29. MODULE_AUTHOR("liwanpeng");  

查看init进程的地址空间效果如下:

阅读(1014) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~