分析linux共享内存的实现
2009-07-04 21:03
309 查看
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操作。
原理:
我们知道,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操作。
相关文章推荐
- 分析linux共享内存的实现
- Linux进程间通信 共享内存实现
- Linux下利用信号量函数和共享内存函数和C语言实现生产者消费者问题
- linux内存源码分析 - 内存压缩(实现流程)
- Linux 内存共享陷阱及分析(shmget,shmat,shmdt,shmctl)
- Linux\Unix IPC进程通信实例分析(一):共享内存通信---文件映射mmap方式
- Linux网络编程--使用epoll,共享内存技术实现高性能的聊天室程序
- Linux初学,利用共享内存,有名管道,select实现两个用户之间的自由对话。
- 一张图深度解析Linux共享内存的内核实现
- linux基础编程 共享内存 通过消息队列实现同步 shmget
- Linux对共享内存的实现
- 进程通信之内存地址映射与共享,同时如何在Linux0.11下实现共享内存
- 读内核源码(Linux 4.9.9)之共享内存的实现
- linux进程内存共享---实现生产者消费者问题
- Linux 基于IPC机制实现进程间的共享内存处理
- linux用户态和kernel之间共享内存 --- remap_pfn_range + mmap的实现方式
- Linux Barrier I/O 实现分析与barrier内存屏蔽 总结
- linux 共享内存实现
- linux下共享内存的实现
- Linux下共享内存通信实现A进程死循环输出A后被C进程处理输出C