IPC(Interprocess Communication)表示进程间通信机制;System V IPC机制主要有消息队列、共享内存、信号量,linux中实现了SysV IPC。

I.SysV IPC创建/获取
消息队列、共享内存、信号量的创建/获取API原型如下:
int msgget(key_t key, int msgflg);
int shmget(key_t key, size_t size, int shmflg);
int semget(key_t key, int nsems, int semflg);

以上API主要用来创建新的IPC或根据key值查找IPC,并返回IPC id;内核实现均调用ipcget:

ipc/util.c:
734 /**
735  * ipcget - Common sys_*get() code
736  * @ns : namsepace
737  * @ids : IPC identifier set
738  * @ops : operations to be called on ipc object creation, permission checks
739  *        and further checks
740  * @params : the parameters needed by the previous operations.
741  *
742  * Common routine called by sys_msgget(), sys_semget() and sys_shmget().
743  */
744 int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
745                         struct ipc_ops *ops, struct ipc_params *params)
746 {
747         if (params->key == IPC_PRIVATE)
748                 return ipcget_new(ns, ids, ops, params);
749         else
750                 return ipcget_public(ns, ids, ops, params);
751 }

i.key
key类型为key_t,即int:

/usr/include/bits/types.h:101:#define    __S32_TYPE      int
/usr/include/bits/typesizes.h:55:#define __KEY_T_TYPE       __S32_TYPE
/usr/include/bits/types.h:155:__STD_TYPE __KEY_T_TYPE __key_t;  /* Type of an IPC key.  */
/usr/include/sys/ipc.h:48:typedef __key_t key_t;

SysV IPC均用key值作为主键,系统级标识出IPC;同时每一个IPC都有一个id与之对应。
key和id都能标识出IPC,区别主要是,key由用户程序提供,以便用户程序标识IPC实现进程间通信;id由系统返回,能快速查找到IPC并使用。
key查找IPC过程:遍历IPC id基数树的叶子结点,找出key对应的IPC。实现为ipc_findkey:

170 /**
171  *      ipc_findkey     -       find a key in an ipc identifier set
172  *      @ids: Identifier set
173  *      @key: The key to find
174  *
175  *      Requires ipc_ids.rw_mutex locked.
176  *      Returns the LOCKED pointer to the ipc structure if found or NULL
177  *      if not.
178  *      If key is found ipc points to the owning ipc structure
179  */
180
181 static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
182 {
183         struct kern_ipc_perm *ipc;
184         int next_id;
185         int total;
186
187         for (total = 0, next_id = 0; total < ids->in_use; next_id++) {
188                 ipc = idr_find(&ids->ipcs_idr, next_id);
189
190                 if (ipc == NULL)
191                         continue;
192
193                 if (ipc->key != key) {
194                         total++;
195                         continue;
196                 }
197
198                 ipc_lock_by_ptr(ipc);
199                 return ipc;
200         }
201
202         return NULL;
203 }

KEY_PRIVATE是一个特殊的key值,不能作为系统范围标识IPC的key;主要用于创建进程私有的IPC(其它进程不能根据key值使用),而非系统级IPC(其它进程能够根据key值使用)。
KEY_PRIVATE值如下:

/usr/include/bits/ipc.h:39:#define IPC_PRIVATE   ((__key_t) 0)   /* Private key.  */

ii.SysV IPC创建
在以下情况创建IPC:
1.key=IPC_PRIVATE
2.key!=IPC_PRIVATE,key值标识的IPC不存在,且flg中IPC_CREATE置位
当创建IPC时,用flg的低9位作为mode(用户、组、其它的读、写、执行权限)来创建IPC

key=IPC_PRIVATE时,调用ipcget_new创建新的IPC;
否则,使用ipcget_public查找key标识的IPC,如果存在校验权限,如果不存在创建IPC或报错。
实现如下:

288 /**
289  *      ipcget_new      -       create a new ipc object
290  *      @ns: namespace
291  *      @ids: IPC identifer set
292  *      @ops: the actual creation routine to call
293  *      @params: its parameters
294  *
295  *      This routine is called by sys_msgget, sys_semget() and sys_shmget()
296  *      when the key is IPC_PRIVATE.
297  */
298 static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
299                 struct ipc_ops *ops, struct ipc_params *params)
300 {
301         int err;
302 retry:
303         err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
304
305         if (!err)
306                 return -ENOMEM;
307
308         down_write(&ids->rw_mutex);
309         err = ops->getnew(ns, params);
310         up_write(&ids->rw_mutex);
311
312         if (err == -EAGAIN)
313                 goto retry;
314
315         return err;
316 }

1.idr_pre_get分配idr缓存,供分配IPC id使用
2.具体的IPC函数,分配相应的IPC。newque、newseg、newary分别创建消息队列、共享内存、信号量

348 /**
349  *      ipcget_public   -       get an ipc object or create a new one
350  *      @ns: namespace
351  *      @ids: IPC identifer set
352  *      @ops: the actual creation routine to call
353  *      @params: its parameters
354  *
355  *      This routine is called by sys_msgget, sys_semget() and sys_shmget()
356  *      when the key is not IPC_PRIVATE.
357  *      It adds a new entry if the key is not found and does some permission
358  *      / security checkings if the key is found.
359  *
360  *      On success, the ipc id is returned.
361  */
362 static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
363                 struct ipc_ops *ops, struct ipc_params *params)
364 {
365         struct kern_ipc_perm *ipcp;
366         int flg = params->flg;
367         int err;
368 retry:
369         err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
370
371         /*
372          * Take the lock as a writer since we are potentially going to add
373          * a new entry + read locks are not "upgradable"
374          */
375         down_write(&ids->rw_mutex);
376         ipcp = ipc_findkey(ids, params->key);
377         if (ipcp == NULL) {
378                 /* key not used */
379                 if (!(flg & IPC_CREAT))
380                         err = -ENOENT;
381                 else if (!err)
382                         err = -ENOMEM;
383                 else
384                         err = ops->getnew(ns, params);
385         } else {
386                 /* ipc object has been locked by ipc_findkey() */
387
388                 if (flg & IPC_CREAT && flg & IPC_EXCL)
389                         err = -EEXIST;
390                 else {
391                         err = 0;
392                         if (ops->more_checks)
393                                 err = ops->more_checks(ipcp, params);
394                         if (!err)
395                                 /*
396                                  * ipc_check_perms returns the IPC id on
397                                  * success
398                                  */
399                                 err = ipc_check_perms(ipcp, ops, params);
400                 }
401                 ipc_unlock(ipcp);
402         }
403         up_write(&ids->rw_mutex);
404
405         if (err == -EAGAIN)
406                 goto retry;
407
408         return err;
409 }

1.idr_pre_get分配idr缓存,供分配IPC id使用
2.如果key对应的IPC不存在,分配IPC
3.如果key对应的IPC存在,做权限等校验

II.SysV IPC共性
SysV IPC有许多共同的属性,如key、id、mode等;IPC共性用kern_ipc_perm表示:

include/linux/ipc.h:
85 /* used by in-kernel data structures */
86 struct kern_ipc_perm
87 {
88         spinlock_t      lock;
89         int             deleted;
90         int             id;
91         key_t           key;
92         uid_t           uid;
93         gid_t           gid;
94         uid_t           cuid;
95         gid_t           cgid;
96         mode_t          mode;
97         unsigned long   seq;
98         void            *security;
99 };

lock:IPC锁
deleted:删除标识
id:IPC id
key:IPC key
uid:IPC所属用户
gid:IPC所属用户组
cuid:IPC创建用户
cgid:IPC创建用户组
mode:用户、用户组、其它的读、写、执行权限
seq:序列号

i.seq
seq用于表示IPC id分配序列号;每次分配IPC id,seq会自增1,到seq_max时会从0重新开始。
1.seq初始化

ipc/util.h:
16 #define SEQ_MULTIPLIER  (IPCMNI)
ipc/util.c:
111 /**
112  *      ipc_init_ids            -       initialise IPC identifiers
113  *      @ids: Identifier set
114  *
115  *      Set up the sequence range to use for the ipc identifier range (limited
116  *      below IPCMNI) then initialise the ids idr.
117  */
118
119 void ipc_init_ids(struct ipc_ids *ids)
120 {
121         init_rwsem(&ids->rw_mutex);
122
123         ids->in_use = 0;
124         ids->seq = 0;
125         {
126                 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
127                 if (seq_limit > USHORT_MAX)
128                         ids->seq_max = USHORT_MAX;
129                  else
130                         ids->seq_max = seq_limit;
131         }
132
133         idr_init(&ids->ipcs_idr);
134 }

2.seq递增

236 /**
237  *      ipc_addid       -       add an IPC identifier
238  *      @ids: IPC identifier set
239  *      @new: new IPC permission set
240  *      @size: limit for the number of used ids
241  *
242  *      Add an entry 'new' to the IPC ids idr. The permissions object is
243  *      initialised and the first free entry is set up and the id assigned
244  *      is returned. The 'new' entry is returned in a locked state on success.
245  *      On failure the entry is not locked and a negative err-code is returned.
246  *
247  *      Called with ipc_ids.rw_mutex held as a writer.
248  */
249
250 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
251 {
279
280         new->seq = ids->seq++;
281         if(ids->seq > ids->seq_max)
282                 ids->seq = 0;
283
284         new->id = ipc_buildid(id, new->seq);
285         return id;
286 }

ii.id
IPC id是由基数树中空闲id与seq计算得到,实现如下:

ipc/util.h:
16 #define SEQ_MULTIPLIER  (IPCMNI)
145 static inline int ipc_buildid(int id, int seq)
146 {
147         return SEQ_MULTIPLIER * seq + id;
148 }
include/linux/ipc.h:
83 #define IPCMNI 32768  /* <= MAX_INT limit for ipc arrays (including sysctl changes) */

如果没有IPC释放的情况时,从基数树中分配的id值会比上次分配id增加1,则IPC id会增大IPCMNI+1=32768+1=32769;情况如下:

[redhat@localhost linux-2.6.32.60]$ ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00000000 98304      redhat     600        393216     2          dest
0x00000000 131073     redhat     600        393216     2          dest
0x00000000 163842     redhat     600        393216     2          dest
0x00000000 196611     redhat     600        393216     2          dest
0x00000000 229380     redhat     600        393216     2          dest
0x00000000 262149     redhat     600        393216     2          dest
0x00000000 622598     redhat     600        393216     2          dest
0x00000000 327687     redhat     600        393216     2          dest
0x00000000 360456     redhat     600        393216     2          dest
0x00000000 393225     redhat     600        393216     2          dest
0x00000000 425994     redhat     600        393216     2          dest
0x00000000 458763     redhat     600        393216     2          dest
0x00000000 491532     redhat     600        393216     2          dest  

iii.mode
mode是在创建IPC时,取自flg的低9位,表示用户、用户组、其它的读、写、执行权限;当IPC已经存在,获取IPC时会做权限校验,由ipcperms实现:

606 /**
607  *      ipcperms        -       check IPC permissions
608  *      @ipcp: IPC permission set
609  *      @flag: desired permission set.
610  *
611  *      Check user, group, other permissions for access
612  *      to ipc resources. return 0 if allowed
613  */
614
615 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
616 {       /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
617         uid_t euid = current_euid();
618         int requested_mode, granted_mode;
619
620         audit_ipc_obj(ipcp);
621         requested_mode = (flag >> 6) | (flag >> 3) | flag;
622         granted_mode = ipcp->mode;
623         if (euid == ipcp->cuid ||
624             euid == ipcp->uid)
625                 granted_mode >>= 6;
626         else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
627                 granted_mode >>= 3;
628         /* is there some bit set in requested_mode but not in granted_mode? */
629         if ((requested_mode & ~granted_mode & 0007) &&
630             !capable(CAP_IPC_OWNER))
631                 return -1;
632
633         return security_ipc_permission(ipcp, flag);
634 }

1.根据进程的身分是IPC的所有者/创建者、组内其它成员、或其它,来确定进程的授权granted_mode
2.计算请求访问IPC的权限requested_mode(读、写、执行);请求权限放在用户、用户组、或其它域中均可,所以做位或运算来计算requested_mode
3.检查请求的权限都有授权

linux SysV IPC实现相关推荐

  1. Linux下IPC方式之共享存储映射(mmap)

    Linux下IPC方式之共享存储映射(mmap) 1. 共享存储映射(mmap) 2. mmap九问 3. mmap实现父子进程通信 4. 匿名映射 5. mmap实现无血缘进程通信 1. 共享存储映 ...

  2. Linux内核IPC命名空间 (一)(用户层信号量机制实现)

    Linux内核IPC机制 在Linux内核中IPC全名称之为进程间通信机制,共分为多种,如下: 信号量 共享内存 消息队列 管道 信号 套接字通信 每一种实现都有其独特特性,一下博客中我们会讲解其中的 ...

  3. 音视频:06.linux系统-IPC进程间通信

    linux系统-IPC进程间通信 1.进程间通信的方式 2.管道(pipe) 3.共享映射区 4.信号 1.进程间通信的方式 文件,管道,信号.信号量,共享映射区(共享内存),消息队列,管道,套接字( ...

  4. 传统的Linux中IPC通信原理

    在了解 Binder 跨进程通信原理之前, 我们先了解一下 Linux 传统的进程间通信的概念和基本原理, 这样有助于我们更好的理解 Binder 的通信原理. 这个部分基本都是理论, 基础不是很好的 ...

  5. Linux的IPC机制(三):Binder

    1. 动态内核可加载模块 && 内存映射 正如上一章所说, 跨进程通信是需要内核空间做支持的. 传统的 IPC 机制如 管道, Socket, 都是内核的一部分, 因此通过内核支持来实 ...

  6. ipc原理linux,传统的Linux中IPC通信原理

    在了解 Binder 跨进程通信原理之前, 我们先了解一下 Linux 传统的进程间通信的概念和基本原理, 这样有助于我们更好的理解 Binder 的通信原理. 这个部分基本都是理论, 基础不是很好的 ...

  7. linux常用ipc技术,LINUX系统编程之IPC

    LINUX系统编程之IPC(Inter Processes Communication) 一.信号 1.信号的产生 软件中断,异步通信,ctrl+c,kill函数,kill命令,硬件异常(段错误),软 ...

  8. RK1126从入门到放弃:番外篇(二)Win10 WSL系统下编译buildroot报错不支持SYSV IPC,导致fakeroot无法正常工作

    Win10的Linux子系统是完全可以直接用来进行嵌入式Linux开发操作的,目前已经非常顺畅地编译通过了U-Boot和内核.但是编译Builtroot的最后阶段,需要使用fakeroot来fake文 ...

  9. Linux 进程间通信-IPC 机制

    Linux 平台上在 Kernel 协调下完成进程之间的相互通信,有多种进程间通信 -- Inter Process Communication(IPC)方式. 1. IPC 分类 按照功能用途来看有 ...

  10. linux各种IPC机制

    原帖发表在IBM的developerworks网站上,是一个系列的文章,作者郑彦兴,通过讲解和例子演示了Linux中几种IPC的使用方式,我觉得很好,在这里做一个保留,能看完的话Linux IPC的基 ...

最新文章

  1. animation动画不生效_关于CSS3的animation使用的一些坑,需要注意下!
  2. MyEclipse中的快捷键
  3. laravel mysql增删改查_Laravel框架数据库操作的增删改三种方式 阿星小栈
  4. 免焊vga3加6接线图_计数器和接近开关两线怎么接,计数器接近开关接线图
  5. win10进程太多怎么优化_用过最好用的Win10优化软件,全方面优化和管理!
  6. python开发环境的安装与配置_Python开发环境的安装配置
  7. 2016年2月23日----Javascript运算符
  8. linux下的僵尸进程 - Zombie
  9. LINQ的ORM功能中对使用sp_executesql语句的存储过程的支持
  10. 【C#】第2章学习要点
  11. Hive,Pig,HBase 傻傻分不清楚
  12. Android反编译实战-去广告
  13. 从技术问题变成RPWT -----------------猛禽
  14. 消息中间件MQ与RabbitMQ
  15. 上海迪士尼将推出虎年新春全新体验
  16. 查看zookeeper的版本号
  17. c语言API用法 查询
  18. pro4重影花屏 surface_【图】- 微软Surfacepro4会花屏模糊抖动怎么回事 - 厦门思明湖滨南路电脑维修 - 厦门百姓网...
  19. iOS-关于M1芯片可以下载APP使用问题
  20. 在生活之中,要活在生活之上

热门文章

  1. 浏览器中performance的基本使用
  2. 公司企业邮箱IP被列入国际黑名单组织怎么解决
  3. java获取时间戳单位秒,如何测试给定的时间戳是以秒或毫秒为单位?
  4. R数据分析:样本量计算的底层逻辑与实操,pwr包
  5. spring动态代理(重要至极)
  6. QCIF CIF 2CIF 4CIF 普及
  7. 单片机之汇编语言和C语言(以PIC单片机为例)
  8. 如何编写好的软件设计文档
  9. 小学认识计算机评课,小学信息技术评课.doc
  10. 操作系统原理(一)操作系统的认识