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操作。

GitHub 加速计划 / li / linux-dash
13
2
下载
A beautiful web dashboard for Linux
最近提交(Master分支:4 个月前 )
186a802e added ecosystem file for PM2 5 年前
5def40a3 Add host customization support for the NodeJS version 5 年前
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐