做网站建设很赚钱吗,重庆蜡像制作,亚马逊雨林有原始人吗,企业网络推广情况介绍Linux 内核中共享内存的实现#xff08;基于 2.6.12#xff09;
核心文件与路径
ipc/shm.c: System V 共享内存系统调用与核心逻辑include/linux/shm.h: 结构体与常量定义#xff08;shmid_kernel 在 #ifdef __KERNEL__ 块内, 仅内核可见#xff09;ipc/util.c: IPC 公共 I…Linux 内核中共享内存的实现基于 2.6.12核心文件与路径ipc/shm.c: System V 共享内存系统调用与核心逻辑include/linux/shm.h: 结构体与常量定义shmid_kernel在#ifdef __KERNEL__块内, 仅内核可见ipc/util.c: IPC 公共 ID/权限/锁管理mm/: 通用内存管理接口页分配、映射核心数据结构shmid_kernel位于include/linux/shm.h// include/linux/shm.h (在 #ifdef __KERNEL__ 块内, 仅内核可见)structshmid_kernel/* private to the kernel */{structkern_ipc_permshm_perm;// IPC 权限/键值/锁structfile*shm_file;// 关联的 shmem 文件, 承载页缓存intid;// 内部 ID (用于 IPC 表索引)unsignedlongshm_nattch;// 当前附加次数(映射该段的进程数)unsignedlongshm_segsz;// 段大小(字节)time_tshm_atim;// 最后 attach 时间time_tshm_dtim;// 最后 detach 时间time_tshm_ctim;// 最后变更时间pid_tshm_cprid;// 创建者 PIDpid_tshm_lprid;// 最后操作 PIDstructuser_struct*mlock_user;// 锁定内存的用户结构(用于 SHM_LOCK)};shmem_inode_info来自 tmpfs/shmem作为shm_file的支撑负责页缓存与换入换出除非 SHM_LOCK 锁定。系统调用路径x86_64 类推sys_shmget→ipc/shm.c:sys_shmget→newseg()创建段分配 shmid_kernel shmem 文件并通过ipc_addid安装到 IPC 表sys_shmat→ipc/shm.c:sys_shmat→do_shmat()检查权限/地址 → 通过do_mmap_pgoff()把shm_file映射到进程用户空间sys_shmdt→ipc/shm.c:sys_shmdt→do_shmdt()卸载映射递减shm_nattchsys_shmctl→ipc/shm.c:sys_shmctl处理IPC_RMID/IPC_SET/IPC_STAT/SHM_LOCK/SHM_UNLOCK关键流程创建段shmget → newseg校验大小不超过shm_ctlmax对齐页向上按页或 SHMLBA。分配shmid_kernelipc_rcu_alloc初始化shm_perm、大小、时间戳、计数。创建支撑文件调用shmem_file_setup()创建匿名 shmem 文件关联到shm_file用于后续映射与页缓存管理。通过ipc_addid(shm_ids, …)安装到 IPC ID 表返回 shmid序号序列。简要实现ipc/shm.c:sys_shmget/newsegasmlinkagelongsys_shmget(key_tkey,size_tsize,intshmflg){structshmid_kernel*shp;interr,id;// 尺寸检查: 不得超过 shm_ctlmaxif(sizeshm_ctlmax)return-EINVAL;// 对齐到页面/SHMLBA (VIPT/TLB 需求)sizeALIGN(size,SHMLBA);// 如果指定 IPC_PRIVATE 或不存在且 IPC_CREAT则创建idnewseg(key,shmflg,size);returnid;// 返回 shmid (序号序列)}staticintnewseg(key_tkey,intshmflg,size_tsize){structshmid_kernel*shp;intid,err;// 分配内核描述符shpipc_rcu_alloc(sizeof(*shp));if(!shp)return-ENOMEM;shp-shm_perm.keykey;shp-shm_perm.mode(shmflgS_IRWXUGO);shp-shm_perm.securityNULL;shp-shm_segszsize;shp-shm_atimshp-shm_dtim0;// 初始未映射/未解绑shp-shm_ctimget_seconds();// 创建时间shp-shm_cpridshp-shm_lpridcurrent-pid;shp-shm_nattch0;// 尚无进程映射// 创建支撑文件 (基于 shmem)shp-shm_fileshmem_file_setup(SYSV0000,size,0);if(IS_ERR(shp-shm_file)){errPTR_ERR(shp-shm_file);ipc_rcu_putref(shp);returnerr;}// 安装到 IPC ID 表idipc_addid(shm_ids,shp-shm_perm,shmmni);if(id-1){fput(shp-shm_file);ipc_rcu_putref(shp);return-ENOSPC;}returnshm_buildid(id,shp-shm_perm.seq);// 返回 shmid}映射shmat → do_shmat权限检查与 ID 校验 (ipc_lock/ipc_checkid/ipcperms)。解析shmaddr/shmflgSHM_RDONLY只读映射SHM_RND地址向下按SHMLBA对齐若指定地址且违反对齐/冲突返回EINVAL增加shm_nattch更新时间shm_atim、shm_lprid。通过do_mmap_pgoff()将shm_file映射到进程用户空间用户态虚拟地址因进程不同而异但指向同一物理页集合。简要实现ipc/shm.c:sys_shmat/do_shmatasmlinkagelongsys_shmat(intshmid,char__user*shmaddr,intshmflg){unsignedlongaddr;interr;// do_shmat 负责权限/地址检查与实际映射errdo_shmat(shmid,shmaddr,shmflg,addr);if(err)returnerr;returnaddr;// 用户态虚拟地址}staticintdo_shmat(intshmid,char__user*shmaddr,intshmflg,unsignedlong*raddr){structshmid_kernel*shp;structfile*file;unsignedlongaddr,flags;// 获取并锁定段shpshm_lock(shmid);if(!shp)return-EINVAL;if(ipc_checkid(shp-shm_perm,shmid)){shm_unlock(shmid);return-EIDRM;}if(ipcperms(shp-shm_perm,(shmflgSHM_RDONLY)?S_IRUGO:S_IRUGO|S_IWUGO)){shm_unlock(shmid);return-EACCES;}fileshp-shm_file;get_file(file);// 引用计数1, 防止映射期间文件被释放// 处理地址/对齐addr(unsignedlong)shmaddr;if(shmflgSHM_RND)addr~(SHMLBA-1);flagsMAP_SHARED;if(shmflgSHM_RDONLY)flags|PROT_READ;elseflags|PROT_READ|PROT_WRITE;// 实际映射: do_mmap_pgoff 返回用户态虚拟地址addrdo_mmap_pgoff(file,addr,shp-shm_segsz,flags,0,0);if(IS_ERR_VALUE(addr)){fput(file);shm_unlock(shmid);returnaddr;}// 更新状态shp-shm_nattch;// 映射计数1shp-shm_atimget_seconds();// 记录最后 attach 时间shp-shm_lpridcurrent-pid;// 记录最后操作 PIDshm_unlock(shmid);*raddraddr;return0;}解除映射shmdt → do_shmdt查找并拆除进程中对应的 VMA 区域按基地址与长度。递减shm_nattch更新时间shm_dtim、shm_lprid。如果段已被标记删除且shm_nattch0释放资源。简要实现ipc/shm.c:sys_shmdt/do_shmdtasmlinkagelongsys_shmdt(char__user*shmaddr){returndo_shmdt((unsignedlong)shmaddr);}staticintdo_shmdt(unsignedlongaddr){structshmid_kernel*shp;intretval;// 通过 VMA 找到对应的 shm 段, 执行 unmapretvalshm_unmap(addr);// 内部执行 find_vma do_munmapif(retval)returnretval;// shm_unmap 中会递减 shm_nattch并在必要时触发销毁return0;}控制shmctlIPC_RMID: 标记段删除若shm_nattch0立即释放shm_destroy否则等待最后一个 detach 后释放。IPC_SET: 更新权限和shm_perm.uid/gid/mode更新时间戳。IPC_STAT: 填充shmid_ds返回用户态。SHM_LOCK/SHM_UNLOCK: 锁定/解锁页以防换出需要 CAP_IPC_LOCK内部通过shm_lock/shm_unlock配合 shmem。简要实现ipc/shm.c:sys_shmctl聚焦 IPC_RMIDasmlinkagelongsys_shmctl(intshmid,intcmd,structshmid_ds__user*buf){structshmid_kernel*shp;interr;down(shm_ids.sem);// IPC 表级锁shpshm_lock(shmid);// 对象锁 获取if(!shp){err-EINVAL;gotoout_up;}if(ipc_checkid(shp-shm_perm,shmid)){err-EIDRM;gotoout_unlock_up;}switch(cmd){caseIPC_RMID:// 从 IPC 表移除标记删除shm_destroy(shp);err0;break;caseIPC_SET:// 更新权限/属主/模式errshmctl_down(shp,cmd,buf);break;caseIPC_STAT:// 拷贝状态给用户errshmctl_stat(shp,buf);break;caseSHM_LOCK:caseSHM_UNLOCK:errshmctl_do_lock(shp,cmd);break;default:err-EINVAL;break;}out_unlock_up:shm_unlock(shmid);out_up:up(shm_ids.sem);returnerr;}释放与回收shm_destroy从 IPC 表移除 (ipc_rmid)关闭shm_file释放shmid_kernel。如果段被 IPC_RMID 标记最后一个shmdt完成后触发真正释放。删除与回收ipc/shm.c:shm_destroystaticvoidshm_destroy(structshmid_kernel*shp){// 从 IPC ID 表移除并标记删除ipc_rmid(shm_ids,shp-shm_perm);// 关闭支撑文件释放引用fput(shp-shm_file);// 释放描述符 (RCU)ipc_rcu_putref(shp);}并发与锁IPC 表锁shm_ids.sem序列化添加/删除。对象锁ipc_lock保护单个段的元数据权限、计数、状态。RCU/引用计数ipc_rcu_alloc/putref管理对象生命周期shm_nattch计数配合删除判定。相关限制2.6.12shmmax单段最大字节数 (/proc/sys/kernel/shmmax)shmmni系统最大段数 (/proc/sys/kernel/shmmni)shmall可用页框总数上限 (/proc/sys/kernel/shmall)SHMLBA映射对齐粒度通常为页或更大对齐到大页边界以兼容 VIPT/TLB 需求重要特性/行为段由 shmemtmpfs文件承载页缓存支持按需分配与换出除非 SHM_LOCK。shmat映射地址位于用户态虚拟地址空间各进程地址可不同但物理页共享。shmdt仅拆映射并递减计数不一定释放物理页IPC_RMIDshm_nattch0才真正销毁。SEM_UNDO不涉及共享内存共享内存的同步需用户态自管信号量/互斥锁等。参考函数/符号2.6.12sys_shmget/sys_shmat/sys_shmdt/sys_shmctlnewseg/do_shmat/do_shmdt/shm_destroyshmem_file_setup支撑文件/do_mmap_pgoff映射ipc_addid/ipc_rmid/ipc_lock/ipc_checkid