Mid 上
最小的共享内存值 4K /proc/sys/kernel/shmmin
最大的共享内存值 32M /proc/sys/kernel/shmmax
可使用的共享内存总量 2M页 /proc/sys/kernel/shmall
使用ipcs 可以查看共享内存的信息 但是mid上并没有包含该命令
下面简述pxa310 上 System v 共享内存的实现
Shmget
创建或获取共享内存
ipc/shm.c
asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
1 从当前进程的task_struct 中得到 ipc 的命名空间
struct ipc_namespace {
struct kref kref;
struct ipc_ids *ids[3];
int sem_ctls[4];
int used_sems;
int msg_ctlmax;
int msg_ctlmnb;
int msg_ctlmni;
size_t shm_ctlmax;
size_t shm_ctlall;
int shm_ctlmni;
int shm_tot;
};
其中 struct ipc_ids *ids[3];
对应着3种IPC机制的ids,分别是信号量,消息队列,以及共享内存
这里只看共享内存的
2 判断传入的key 是否为 IPC_PRIVATE(0),
IPC_PRIVATE 表示是父子进程间内存共享
这个时候就需要创建一个新的共享段
将需求size 进行4K上取整,并取得所需page数
如果之间的所有page数与当前page数大于2M ,则返回失败
如果这个size 小于1 或大于32M 则返回失败
每个共享内存区都有一个非常重要的数据结构
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
int id;
unsigned long shm_nattch;
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 对应于特殊文件系统shm中的一个文件
访问路径 /proc/sysv/shm
分配了这样一个结构体后,将相应的key,flag 按照输入进行了设置,
将结构体指针放入 共享内存对应的ids 中的entries中。
shmid_kernel 中的id 为 32768 * seq + 我们传入的id
这个seq 存放在共享内存对应的ids 中,每次添加一个元素后++
专门用来计算id
如果共享内存不是用于父子进程间,
首先就得在entries 中查找 ,指定的id是否存在
如果存在,但出入的flag 又指定必要创建,返回失败
否则创建新的shmid_kernel 放入ids中,流程与前面一样
如果找到了但没有创建标志
已经在的shmid_kernel结构中的大小不得小于本次调用传入的大小,否则失败
接下来检查用户,组和其他权限,
再次生存一个内部id号返回,计算公式和前面一致
Shmat
映射到进程的地址空间
asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
1 首先对输入的shmid进行检查
如果小于0,直接退出
如果用户设置了映射地址 shmaddr
检查该地址,是否是4K对齐的,如果没有对齐且有对齐标志
则下对齐,否则返回失败。
如果没有指定 shmaddr,但又置了remap标志,返回失败
根据shmflg 设置访问模式
找到对应的shmid_kernel 结构 ,使用前面提到的计算公式验证id
从 shm_file中获取dentry和安装点
找出一个空闲的FILE 结构 ,设置 file_operations ,path ,地址空间 和私有数据后
调用do_mmap 进行映射
首先需要找到一个没有影射过的区域
怎么来找呢?
前面设置file_operations 的时候设置了如下结构
static const struct file_operations shm_file_operations = {
.mmap = shm_mmap,
.fsync = shm_fsync,
.release = shm_release,
.get_unmapped_area = shm_get_unmapped_area,
};
就是调用 shm_get_unmapped_area 来获取一块没有影射的区域
对应 arch_get_unmapped_area
Arch/arm/mm/mmap.c
简单的说就是 生成一个满足条件的vm_area_struct,将其插入进程的虚拟地址描述符 构成的二叉树中。
Shmdt
asmlinkage long sys_shmdt(char __user *shmaddr)
将共享内存从当前进程中分离
首先通过 shmaddr 在二叉树中找到第一个满足块的结束地址大于shmaddr的
vm_area_struct 出来,如果满足条件就直接删掉。
…..
Shmctl
asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
System V 共享内存
以 IPC_RMID 为例
通过 shmid找到对应的shmid_kernel
通过公式验证id
通过当前的进程的euid判断是否有权限
删除 对应的shmid_kernel 结构
总结
涉及到存储管理和文件系统。
System V 共享内存 是以文件的形式组织在特殊文件系统shm 中的,而shm的安装点在交换分区上 。 这样就决定了如下特点
1 从不写入磁盘文件,系统重新引导后内容消失
2 通信双方进程消失后 ,共享内存热然存在,除非显示删除。不用考虑进程终止对通信的影响。
3 没有实现同步。 需要与其他方式结合使用。