Shm是Unix进程间通信最常见也最重要的方法之一。

它是如何实现的呢?

我们来看下入下内容。

初始化:

void shm_init (void)

{

int id;

for (id = 0; id < SHMMNI; id++)

shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;

shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;

shm_lock = NULL;

return;

}寻找共享内存的ID。

static int findkey (key_t key)

{

int id;

struct shmid_ds *shp;

for (id=0; id <= max_shmid; id++) {

while ((shp = shm_segs[id]) == IPC_NOID)

sleep_on (&shm_lock);

if (shp == IPC_UNUSED)

continue;

if (key == shp->shm_perm.key)

return id;

}

return -1;

}

获取共享内存:

int sys_shmget (key_t key, int size, int shmflg)

{

struct shmid_ds *shp;

int id = 0;

if (size < 0 || size > SHMMAX)

return -EINVAL;

if (key == IPC_PRIVATE)

return newseg(key, shmflg, size);

if ((id = findkey (key)) == -1) {

if (!(shmflg & IPC_CREAT))

return -ENOENT;

return newseg(key, shmflg, size);

}

if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))

return -EEXIST;

shp = shm_segs[id];

if (shp->shm_perm.mode & SHM_DEST)

return -EIDRM;

if (size > shp->shm_segsz)

return -EINVAL;

if (ipcperms (&shp->shm_perm, shmflg))

return -EACCES;

return shp->shm_perm.seq*SHMMNI + id;

}

共享内存属性设置:

int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)

{

struct shmid_ds *shp, tbuf;

struct ipc_perm *ipcp;

int id, err;

if (cmd < 0 || shmid < 0)

return -EINVAL;

if (cmd == IPC_SET) {

if (!buf)

return -EFAULT;

err = verify_area (VERIFY_READ, buf, sizeof (*buf));

if (err)

return err;

memcpy_fromfs (&tbuf, buf, sizeof (*buf));

}

switch (cmd) { /* replace with proc interface ? */

case IPC_INFO:

{

struct shminfo shminfo;

if (!buf)

return -EFAULT;

shminfo.shmmni = SHMMNI;

shminfo.shmmax = SHMMAX;

shminfo.shmmin = SHMMIN;

shminfo.shmall = SHMALL;

shminfo.shmseg = SHMSEG;

err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo));

if (err)

return err;

memcpy_tofs (buf, &shminfo, sizeof(struct shminfo));

return max_shmid;

}

case SHM_INFO:

{

struct shm_info shm_info;

if (!buf)

return -EFAULT;

err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));

if (err)

return err;

shm_info.used_ids = used_segs;

shm_info.shm_rss = shm_rss;

shm_info.shm_tot = shm_tot;

shm_info.shm_swp = shm_swp;

shm_info.swap_attempts = swap_attempts;

shm_info.swap_successes = swap_successes;

memcpy_tofs (buf, &shm_info, sizeof(shm_info));

return max_shmid;

}

case SHM_STAT:

if (!buf)

return -EFAULT;

err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));

if (err)

return err;

if (shmid > max_shmid)

return -EINVAL;

shp = shm_segs[shmid];

if (shp == IPC_UNUSED || shp == IPC_NOID)

return -EINVAL;

if (ipcperms (&shp->shm_perm, S_IRUGO))

return -EACCES;

id = shmid + shp->shm_perm.seq * SHMMNI;

memcpy_tofs (buf, shp, sizeof(*shp));

return id;

}

shp = shm_segs[id = shmid % SHMMNI];

if (shp == IPC_UNUSED || shp == IPC_NOID)

return -EINVAL;

ipcp = &shp->shm_perm;

if (ipcp->seq != shmid / SHMMNI)

return -EIDRM;

switch (cmd) {

case SHM_UNLOCK:

if (!suser())

return -EPERM;

if (!(ipcp->mode & SHM_LOCKED))

return -EINVAL;

ipcp->mode &= ~SHM_LOCKED;

break;

case SHM_LOCK:

/* Allow superuser to lock segment in memory */

/* Should the pages be faulted in here or leave it to user? */

/* need to determine interaction with current->swappable */

if (!suser())

return -EPERM;

if (ipcp->mode & SHM_LOCKED)

return -EINVAL;

ipcp->mode |= SHM_LOCKED;

break;

case IPC_STAT:

if (ipcperms (ipcp, S_IRUGO))

return -EACCES;

if (!buf)

return -EFAULT;

err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));

if (err)

return err;

memcpy_tofs (buf, shp, sizeof(*shp));

break;

case IPC_SET:

if (suser() || current->euid == shp->shm_perm.uid ||

current->euid == shp->shm_perm.cuid) {

ipcp->uid = tbuf.shm_perm.uid;

ipcp->gid = tbuf.shm_perm.gid;

ipcp->mode = (ipcp->mode & ~S_IRWXUGO)

| (tbuf.shm_perm.mode & S_IRWXUGO);

shp->shm_ctime = CURRENT_TIME;

break;

}

return -EPERM;

case IPC_RMID:

if (suser() || current->euid == shp->shm_perm.uid ||

current->euid == shp->shm_perm.cuid) {

shp->shm_perm.mode |= SHM_DEST;

if (shp->shm_nattch <= 0)

killseg (id);

break;

}

return -EPERM;

default:

return -EINVAL;

}

return 0;

}

SHM的SWAP:

/*

* Goes through counter = (shm_rss << prio) present shm pages.

*/

static unsigned long swap_id = 0; /* currently being swapped */

static unsigned long swap_idx = 0; /* next to swap */

int shm_swap (int prio)

{

unsigned long page;

struct shmid_ds *shp;

struct shm_desc *shmd;

unsigned int swap_nr;

unsigned long id, idx, invalid = 0;

int counter;

counter = shm_rss >> prio;

if (!counter || !(swap_nr = get_swap_page()))

return 0;

check_id:

shp = shm_segs[swap_id];

if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) {

swap_idx = 0;

if (++swap_id > max_shmid)

swap_id = 0;

goto check_id;

}

id = swap_id;

check_table:

idx = swap_idx++;

if (idx >= shp->shm_npages) {

swap_idx = 0;

if (++swap_id > max_shmid)

swap_id = 0;

goto check_id;

}

page = shp->shm_pages[idx];

if (!(page & PAGE_PRESENT))

goto check_table;

swap_attempts++;

if (--counter < 0) { /* failed */

if (invalid)

invalidate();

swap_free (swap_nr);

return 0;

}

for (shmd = shp->attaches; shmd; shmd = shmd->seg_next) {

unsigned long tmp, *pte;

if ((shmd->shm_sgn >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {

printk ("shm_swap: id=%ld does not match shmd\n", id);

continue;

}

tmp = shmd->start + (idx << PAGE_SHIFT);

if (tmp >= shmd->end) {

printk ("shm_swap: too large idx=%ld id=%ld PANIC\n",idx, id);

continue;

}

pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);

if (!(*pte & 1)) {

printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",

id, shmd->start, idx);

*pte = 0;

continue;

}

pte = (ulong *) (PAGE_MASK & *pte);

pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));

tmp = *pte;

if (!(tmp & PAGE_PRESENT))

continue;

if (tmp & PAGE_ACCESSED) {

*pte &= ~PAGE_ACCESSED;

continue;

}

tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;

*pte = tmp;

mem_map[MAP_NR(page)]--;

shmd->task->rss--;

invalid++;

}

if (mem_map[MAP_NR(page)] != 1)

goto check_table;

page &= PAGE_MASK;

shp->shm_pages[idx] = swap_nr;

if (invalid)

invalidate();

write_swap_page (swap_nr, (char *) page);

free_page (page);

swap_successes++;

shm_swp++;

shm_rss--;

return 1;

} 其实,共享内存并非神秘的魔域。它也就仅仅是个资源管理方案而已。

linux实现内存共享,Linux共享内存实现相关推荐

  1. linux shared,从 0 开始学习 Linux 系列之「22.共享内存 Shared Memory」

    共享内存 版权声明:本文为 cdeveloper 原创文章,可以随意转载,但必须在明确位置注明出处! 共享内存 Shared Memory 这次我们来学习在 Linux 中最快的一种 IPC 方式:共 ...

  2. linux ipc shmget 例子,Linux IPC之共享内存C 事例(示例代码)

    简介 共享内存(shared memory)是最简单的Linux进程间通信方式之一.使用共享内存,不同进程可以对同一块内存进行读写.由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不需要进行 ...

  3. 【Linux Program】信号量、共享内存和消息队列

    系列文章: 文件操作 数据管理 进程和信号 POSIX 线程 进程间通信:管道 信号量共享内存和消息队列 套接字 文章目录 1. 信号量 1.1 信号量的定义 1.2 Linux 的信号量机制 1.3 ...

  4. Linux进程间通信详解(四) —— 共享内存及函数

    共享内存的概念 共享内存是指多个进程可以把一段内存共同的内存映射到自己的进程空间中,从而实现数据的共享和传输,它是存在与内核级别的一种资源,是所有进程间通信中方式最快的一种. 在shell环境下可以使 ...

  5. linux map内存在哪里分配,brk  mmap  madvise 内存分配以及共享内存

    mmap() vs read()/write()/lseek() 通过strace统计系统调用的时候,经常可以看到mmap()与mmap2().系统调用mmap()可以将某文件映射至内存(进程空间), ...

  6. linux共享内存原IPCS,共享内存相关(ipcs/ipcrm)

    在Linux进程通信中,共享内存的应用是比较普遍,把自己学习过的资料作一个小结吧! 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区.在/proc/sys/kernel/目录下,记录着共 ...

  7. linux进程间通信:system V 共享内存

    文章目录 思维导图如下 通信原理 优势 运行流程 编程接口 编程实例 思维导图如下 通信原理 多个进程共享物理内存的同一块区域(通常称之为"段":segment) 抛弃了内核态消息 ...

  8. Linux 进程间通信:管道、共享内存、消息队列、信号量

    进程间通信 管道 共享内存 消息队列 信号量 进程间通信 https://blog.csdn.net/qq_35423154/article/details/105294963 在之前的一篇博客中讲过 ...

  9. 【Linux】进程间通信--systemV标准--共享内存

    文章目录 systemV 标准 共享内存通信原理 共享内存的理解 共享内存的创建--shmget函数 查看共享内存和释放共享内存方式 挂在共享内存--shmat函数 去挂在共享内存--shmdt函数 ...

  10. linux查看设备内存代码,Linux下内存查看命令(示例代码)

    在Linux下面,我们常用top命令来查看系统进程,top也能显示系统内存.我们常用的Linux下查看内容的专用工具是free命令. Linux下内存查看命令free详解: 在Linux下查看内存我们 ...

最新文章

  1. SQL Server 2005 和JBOSS 4 系统运行缓慢--高并发系统探讨(1)
  2. SQL Server表分区【转】
  3. Go语言中*和的区别
  4. SQL注入-SQL注入的WAF绕过(十六)
  5. c++向mysql通信_C++连接MySQL
  6. 树的度,结点,叶子结点,二叉树
  7. numpy创建zeros数组时报错TypeError: Cannot interpret ‘8‘ as a data type
  8. time和datatime模块
  9. Python学习笔记:微积分计算
  10. Html 5/CSS 的学习(二) —— Bootstrap 导航栏
  11. html css没有反应,只有CSS和HTML的标签没有正确响应
  12. ENVI软件中决策树分类和监督分类算法比较
  13. 希捷移动硬盘打不开怎么办?
  14. Excel 2013 基础视频教程上线了
  15. android nat64,dpvs学习笔记: 18 nat64 的实现
  16. 小米商城网页制作(附源码)
  17. 使用ffmpeg来将mp4视频转换成gif格式图片
  18. 2020四川大学计算机考研真题,2020年四川大学计算机考研初试874真题回忆!
  19. 洛谷 P5594 【XR-4】模拟赛 视频讲解(二维数组、模拟)
  20. 天翼云服务器性能评测,4H8G贵阳节点性能跑分

热门文章

  1. python入门三:文件操作
  2. 所有的胜利,与征服自己的胜利比起来,都是微不足道。
  3. POJ 2115 模线性方程 ax=b(mod n)
  4. java制作网站的原理_代码生成器原理
  5. Python+OpenGL实现虚拟场景中不同物体的拾取与选择
  6. 微课|玩转Python轻松过二级:第3章课后习题解答5
  7. c51单片机蜂鸣器程序C语言响,单片机蜂鸣器响生日快乐编程程序
  8. java url拦截器框架_使用Spring Interceptor实现URL访问校验
  9. 关于流(文件)的输入,输出与调用(fprintf,fscanf)
  10. jq ajax调用php函数,jQuery