1      IPC概述

linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同。前者对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,通信进程局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。Linux则把两者继承了下来,如图示:

linux下进程间通信的几种主要手段简介:

1)管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;

2)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数);

3)报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

4)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。

5)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。

6)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

2      IPC namespace

2.1      功能

Ipc namespace的作用是使划分到不同ipc namespace的进程组通信上隔离,无法通过消息队列、共享内存、信号量方式通信,但没有对所述所有IPC通信方式隔离。

2.2      实现

下面我们以消息队列和共享内存为例进行说明

2.2.1      消息队列

IPC命名空间是一个扁平的结构,在ipc_namespace.h中定义了IPC命名空间的数据结构:

其中最关键的就是

每一个struct ipc_ids结构描述了一类IPC资源,在IPC名空间之前,内核定义了三个全局的ipc_ids结构实例,分别代表信号量、消息队列和共享内存。

这就意味着所有的进程都能够通过这三个全局资源进行通信。IPC命名空间取消了这三个全局实例,放入了ipc_namespace中,通过三个宏访问某一个IPC命名空间的IPC资源:

这意味着不同的IPC命名空间不能访问彼此的ipc_ids成员,先看一下ipc_ids的作用,其定义在ipc_namespace.h中

接下来再看一下struct idr的定义,在idr.h中:

一并将idr_layer的第一列举出来,在idr.h中:

结合idr和idr_layer结构,可以看得出来,idr是一棵树,只不过是每个节点都有32个叶子节点的大树。接下来结合消息队列分析下idr的作用。

分析下创建一个消息队列的过程:

接下来调用了do_msgget函数,传入的第一个参数是current->nsproxy->ipc_ns,结合前面的知道是创建该消息队列的进程的IPC命名空间;第二个参数key:消息队列关联的键;msgflg:消息队列的建立标志和存取权限。

这里的ns就是上面传下来的当前进程的IPC命名空间,msg_ops是一个操作集合,根据msgflg确定该执行集合中的哪个函数。Key和msgflg被保存到了msg_params中,然后调用了msg_ids(ns)宏,根据前面的介绍:

知道是获取了IPC命名空间中的ipc_ids的消息队列相关的实例。

根据上面的注释可以看到如果,key=0那么接下来调用ipcget_new创建一个私有的消息队列,通常key的值都会大于0,所以这里选择ipcget_public函数分析,传给ipcget_public的参数仍然是IPC命名空间;ipc_ids实例;msg操作集;key和msgflg,req_id=-1。

关注下蓝色的函数idr_pre_get,这个函数主要是为前面说到的idr树分配内存,并创建好这棵树,具体过程不作分析。

接下来调用了一个关键的函数

这里看到了上面传入的IPC命名空间里消息队列相关的ipc_ids实例,这个函数执行后返回的是一个kern_ipc_perm结构的指针,struct kern_ipc_perm是三类IPC资源中共同的一部分,看一下信号量、消息队列和共享内存数据结构的定义:

有图中蓝色的部分看到,都定义了一个kern_ipc_perm结构,也就是说找到了kern_ipc_perm结构的实例也就找到了信号量或者消息队列或者共享内存的实例。继续看ipc_findkey函数:

分析蓝色部分的idr_find函数,传入的参数是ids中的idr成员ipcs_idr,也就是这个ids管理的idr树:

可以看得出来这两个函数是通过key到ids管理的idr树中查找和key相符合的kern_ipc_perm实例,对于新创建的消息队列,这里查找肯定会返回空。继续回到ipcget_public函数中:

如果返回空,那么最后调用了msg操作集中的getnew函数,

前面分析过getnew被赋值为newque,分析下newque函数:

分配一个消息队列,包含了一个kern_ipc_perm结构。

这个函数是关键,前面分配的消息队列的kern_ipc_perm结构被作为参数传入&msq->q_perm,ids实例也被作为参数传入,ipc_addid函数不具体分析了,起作用就是在&msg_ids(ns)管理的idr树中找到一个空闲节点,将&msq->perm存入这个节点中,同时返回这个节点的序号,也就是这个函数的返回值给id,最后这个函数返回的msq->q_perm.id也就是节点的序号,最后msgget返回的句柄也就是这个id号,程序可以用这个id号进行发送消息。

总结起来,命名空间和各类IPC资源之间的关系如下图:

2.2.2      共享内存

共享内存的创建过程与msg基本相同,只是getnew指向的函数改为newseg。

前面一些初始化的操作,最关键的步骤就是shmem_file_setup()

在全局的tmpfs中申请一个inode并设置文件大小,申请一个sturct file和这个inode绑定并存储到struct shmid_kernel中,后面其他进在获取这块共享内存时就从shmid_kernel开始的。

下面我们看下其他进程如果获取这块共享内存:

系统调用接口shmat

很明显关键操作是do_shmat,这个函数的入参ret返回的就是我们希望得到的,共享内存在本进程对应的虚拟地址,下面看下它是如何实现的

通过current->nsproxy->ipc_ns获取当前IPC命名空间,再获取前述struct shmid_kernel,所以这一步就保证了只有在相同命名空间内的进程才能获取ID为shmid的共享内存。然后再申请一个struct file和上一步的inode绑定并设置ops。

接下来先检查下当前进程是否有足够虚拟地址空间来完成这次映射,最后调用do_mmap完成实际的映射,返回映射地址user_addr传给用户态。 不同进程获取的这个地址可能不一样,但真实的物理地址都是指向前述newseg申请的tmpfs。

ipc_namespace相关推荐

  1. Linux Kernel Namespace实现: namespace API介绍

    1)前言 随着docker的出现, Linux container这种轻量级虚拟化方案越来越在产业里得到大规模的部署和应用. 而Namespace是Linux Container的基础, 了解name ...

  2. linux内核PID管理--命名空间

    PID即进程描述符在linux kernel中的分配和管理比较复杂. 本文分析了其相关数据结构以及函数. (代码基于v3.0.3) 和PID相关的数据结构有 [cpp] view plaincopy ...

  3. Linux内核的namespace机制分析

    1.  Linux内核namespace机制 Linux Namespaces机制提供一种资源隔离方案.PID,IPC,Network等系统资源不再是全局性的,而是属于某个特定的Namespace.每 ...

  4. linux container容器技术框架性理解

    我对container原理的一些理解(基于linux kernel 2.6.38) by kin 2011.04.17 ======================================== ...

  5. Kubernetus自传

    Kubernetus自传 1. 前言 2. Kubernetus介绍 3. Kubernetus组件 3.1 Master Node 3.2 Work Node 4. Kubernetus重要术语 4 ...

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

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

  7. 阅读 Linux 内核源码——共享内存

    介绍 我看的是linux-4.2.3的源码.参考了<边干边学--Linux内核指导>(鬼畜的书名)第16章内容,他们用的是2.6.15的内核源码. 现在linux中可以使用共享内存的方式有 ...

  8. handler原子锁_深入Linux内核架构——锁与进程间通信

    Linux作为多任务系统,当一个进程生成的数据传输到另一个进程时,或数据由多个进程共享时,或进程必须彼此等待时,或需要协调资源的使用时,应用程序必须彼此通信. 一.控制机制 1.竞态条件 几个进程在访 ...

  9. c++ namespace和linux namespace

    一.c++中的namespace 在C++语言中,命名空间使用namespace来声明,并使用{ }来界定命名空间的作用域.命名空间可以是全局的,也可以位于另一命名空间之中:但不能在类和代码块之中.按 ...

最新文章

  1. MATLAB简易验证码识别程序介绍
  2. 【深度学习】深入理解Batch Normalization批标准化
  3. 打印机支持打印html页面吗,vue下调用打印功能,打印html页面
  4. wxWidgets:wxCloseEvent类用法
  5. PHP 依赖镜像出问题后,阿里工程师的一顿“神操作“令人叫绝!
  6. 敏捷方法在测试计划中的应用
  7. python判断天数_python判断输入日期是该年的第几天
  8. python抓取数据包_利用python-pypcap抓取带VLAN标签的数据包方法
  9. ThinkPHP之add、save无法添加、修改的解决方案
  10. 中国内镜逆行胰胆管造影装置市场趋势报告、技术动态创新及市场预测
  11. debian、ubuntu安装metasploit通用方法
  12. 月光博客:我的知识管理工具列表(强烈推荐收藏)
  13. 支持wmv、mpg、mov、avi格式的网页视频播放代码
  14. [buuctf.reverse] 33到50题
  15. 【转】楼天城楼教主的acm心路历程(作为励志用)
  16. 【Javascript】shift、unshift、pop、push的区别
  17. 互联网广告的基本概念
  18. 学Android必须懂的
  19. Java实现Excel操作的方式
  20. 最大公约数(Java)

热门文章

  1. element弹出toast提示窗口
  2. 【HTML】HTML作业----实现Windows计算器
  3. comsol移动网格_请问一下comsol中怎么设置动网格?
  4. 计算机云共享盘,计算机文件共享
  5. 多媒体发布系统介绍和应用领域
  6. MAC苹果系统安装数字证书的方法
  7. 用Tkinter打造自己的Python IDE开发工具(5)利用HP_tka模块设计自己的中文代码编辑器
  8. 16年4月21号:Git版本控制工具的使用
  9. Android5.1.+ getRunningAppProcesses()获取运行中进程(第三方开源库)
  10. jquery中.eq()与:eq()的区别