本篇内容主要讲解“linux进程通信共享内存原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux进程通信共享内存原理是什么”吧!
1 有一个全局的结构体数据,每次需要一块共享的内存时(shmget),从里面取一个结构体,记录相关的信息。
struct shmid_ds { // 权限相关 struct ipc_perm shm_perm; /* operation perms */ // 共享内存的大小 int shm_segsz; /* size of segment (bytes) */ time_t shm_atime; /* last attach time */ time_t shm_dtime; /* last detach time */ time_t shm_ctime; /* last change time */ // 创建该结构体的进程 unsigned short shm_cpid; /* pid of creator */ unsigned short shm_lpid; /* pid of last operator */ // 当前使用该共享内存的进程数 short shm_nattch; /* no. of current attaches */ /* the following are private */ // 共享内存的页数 unsigned short shm_npages; /* size of segment (pages) */ // 指向共享的物理内存的指针 unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ // 使用该共享内存的进程信息 struct vm_area_struct *attaches; /* descriptors for attaches */}
AI代码助手复制代码
2 调用shmat的时候传入shmget返回的id。shmat根据id找到对应的shmid_ds 结构体。新建一个vm_area_struct结构体。开始地址和结束地址根据shmid_ds 中的信息计算,也就是用户申请的大小。接着把vm_area_struct插入进程中管理vm_area_struct的avl树。并且把一些上下文信息保存到页表项。缺页中断的时候在shm_swap_in里使用。
shm_sgn = shmd->vm_pte + ((shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT); for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE, shm_sgn += (1 << SHM_IDX_SHIFT)) { page_dir = pgd_offset(shmd->vm_task,tmp); page_middle = pmd_alloc(page_dir,tmp); if (!page_middle) return -ENOMEM; page_table = pte_alloc(page_middle,tmp); if (!page_table) return -ENOMEM; pte_val(*page_table) = shm_sgn; }
AI代码助手复制代码
3 进程访问共享内存范围中的地址时,触发缺页中断。
void do_no_page(struct vm_area_struct * vma, unsigned long address, int write_access){ pte_t * page_table; pte_t entry; unsigned long page; // 在进程页表里获取address对应的页表项地址 page_table = get_empty_pgtable(vma->vm_task,address); // 分配失败则返回 if (!page_table) return; entry = *page_table; // 已经建立了虚拟地址到物理地址的映射,返回 if (pte_present(entry)) return; // 还没有建立映射 if (!pte_none(entry)) { do_swap_page(vma, address, page_table, entry, write_access); return; } ......}
AI代码助手复制代码
在缺页中断中调用do_swap_page。
static inline void do_swap_page(struct vm_area_struct * vma, unsigned long address, pte_t * page_table, pte_t entry, int write_access){ pte_t page; if (!vma->vm_ops || !vma->vm_ops->swapin) { swap_in(vma, page_table, pte_val(entry), write_access); return; } page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry)); if (pte_val(*page_table) != pte_val(entry)) { free_page(pte_page(page)); return; } if (mem_map[MAP_NR(pte_page(page))] > 1 && !(vma->vm_flags & VM_SHARED)) page = pte_wrprotect(page); ++vma->vm_task->mm->rss; ++vma->vm_task->mm->maj_flt; // 写入物理地址 *page_table = page; return;}
AI代码助手复制代码
其中vma->vm_ops->swapin对应shm.c的shm_swap_in
pte_val(pte) = shp->shm_pages[idx]; // 还没有分配物理内存 if (!pte_present(pte)) { // 分配物理内存 unsigned long page = get_free_page(GFP_KERNEL); ... // 记录物理地址 shp->shm_pages[idx] = pte_val(pte); } mem_map[MAP_NR(pte_page(pte))]++; return pte_modify(pte, shmd->vm_page_prot);
AI代码助手复制代码
如果还没分配物理地址则分配,否则直接范围已经分配的地址。do_swap_page函数的最后一句会把物理地址写入进程的页表项。下次就不会缺页中断了。
同理,其他进程共享该块内存的时候,如果访问范围内的地址,处理过程是类似的。进程访问某一个地址,发生缺页中断,然后进入do_swap_page函数处理,再到shm_swap_in。发现这时候共享内存已经映射了物理地址。最后改写自己的页表项。因为各个进程都对应同一块内存,所以操作的时候会互相感知,实现通信。
到此,相信大家对“linux进程通信共享内存原理是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4217331/blog/4379499