分析linux共享内存的实现

  • Post author:
  • Post category:linux





Linux


对共享内存的实现,在

2.6

采用了内存映射技术。对于内存共享,主要集中在三个内核函数,他们是

do_shmat



sys_shmat



sys_shmdt

。其中,

sys_shmat

调用了

do_shmat

最终实现了共享内存的

attach



sys_shmdt

实现了共享内存的

detach



destroy

。下面我主要对这三个函数的源码进行分析。在分析之前,首先介绍共享内存实现原理。










原理:











我们知道,

LINUX

的进程拥有自己独立的地址空间,这点和

vxworks

是不同的。系统中多个进程共享同一内存段,可以通过系统提供的共享内存机制进行。当进程向系统提出创建或附着共享内存的申请的时候,内核会为每一个新的共享内存段提供一个


shmid_kernel

的数据结构来维护共享段和文件系统之间的关系(也可以理解成共享内存段和文件系统之间建立关系的桥梁)。下面就是这个数据结构:


这个数据结构定义在

shm.h

头文件中




struct shmid_kernel /* private to the kernel */





{










struct kern_ipc_perm


shm_perm; //


访问权限的信息









struct file *




shm_file; //


指向虚拟文件系统的指针









unsigned long


shm_nattch; //


有多少个进程

attach

上了这个共享内存段









unsigned long


shm_segsz; //


共享内存段大小









//


以下是一些访问时间的相关信息









time_t


shm_atim;







time_t


shm_dtim;







time_t


shm_ctim



















pid_t


shm_cprid;







pid_t


shm_lprid;







struct user_struct


*mlock_user;





};




该数据结构中最重要的部分就是



shm_file



这个字段。它指向了共享内存对应的文件。在该结构中有一个字段,



f_mapping



,它指向了该内存段使用的页面(物理内存)。同时,结构中,也包含一个字段,



f_path



,用于指向文件系统中的文件



(dentry->inode)



,这样就建立了物理内存和文件系统的桥梁。当进程需要创建或者



attach



共享内存的时候,在用户态,会先向虚拟内存系统申请各自的



vma_struct



,并将其插入到各自任务的红黑树中,该结构中有一个成员



vm_file



,它指向的就是



struct file(shm_file)



。这样虚拟内存、共享内存(文件系统)和物理内存就建立了连接。






接着我们来看看主要的函数:




do_shmat









1.








这个函数首先根据



shared memory







id



,在内核中查找相应的



shmid_struct










shp = shm_lock_check(ns, shmid);







if (IS_ERR(shp)) {








err = PTR_ERR(shp);







goto out;







}









2.








对访问者进行访问权限检查






if (ipcperms(&shp->shm_perm, acc_mode))







goto out_unlock;






3.








获取共享内存对应的文件的信息。



获取文件表项






path.dentry = dget(shp->shm_file->f_path.dentry);










获取挂接点






path.mnt


= shp->shm_file->f_path.mnt;










共享内存引用计数自增






shp->shm_nattch++;










通过



i



节点获取文件大小






size = i_size_read(path.dentry->d_inode);









4.








分配相应的数据结构,并进行初始化。






err = -ENOMEM;














slab



分配其中分配



shm_file_data



数据结构






sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);







if (!sfd)







goto out_put_dentry;










分配一个



struct file



的数据结构






file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);







if (!file)







goto out_free;










初始化



file










file->private_data = sfd;







file->f_mapping = shp->shm_file->f_mapping;







sfd->id = shp->shm_perm.id;







sfd->ns = get_ipc_ns(ns);







sfd->file = shp->shm_file;







sfd->vm_ops = NULL;









5.








最后进行内存映射,完成



attach



操作。






user_addr = do_mmap (file, addr, size, prot, flags, 0);








sys_shmat







他是系统调用函数,他调用了



do_shmat











sys_shmdt







首先查找相应的



vma



,如果找到执行



ummap



操作。



版权声明:本文为tq02h2a原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。