linux SysV IPC实现
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实现相关推荐
- Linux下IPC方式之共享存储映射(mmap)
Linux下IPC方式之共享存储映射(mmap) 1. 共享存储映射(mmap) 2. mmap九问 3. mmap实现父子进程通信 4. 匿名映射 5. mmap实现无血缘进程通信 1. 共享存储映 ...
- Linux内核IPC命名空间 (一)(用户层信号量机制实现)
Linux内核IPC机制 在Linux内核中IPC全名称之为进程间通信机制,共分为多种,如下: 信号量 共享内存 消息队列 管道 信号 套接字通信 每一种实现都有其独特特性,一下博客中我们会讲解其中的 ...
- 音视频:06.linux系统-IPC进程间通信
linux系统-IPC进程间通信 1.进程间通信的方式 2.管道(pipe) 3.共享映射区 4.信号 1.进程间通信的方式 文件,管道,信号.信号量,共享映射区(共享内存),消息队列,管道,套接字( ...
- 传统的Linux中IPC通信原理
在了解 Binder 跨进程通信原理之前, 我们先了解一下 Linux 传统的进程间通信的概念和基本原理, 这样有助于我们更好的理解 Binder 的通信原理. 这个部分基本都是理论, 基础不是很好的 ...
- Linux的IPC机制(三):Binder
1. 动态内核可加载模块 && 内存映射 正如上一章所说, 跨进程通信是需要内核空间做支持的. 传统的 IPC 机制如 管道, Socket, 都是内核的一部分, 因此通过内核支持来实 ...
- ipc原理linux,传统的Linux中IPC通信原理
在了解 Binder 跨进程通信原理之前, 我们先了解一下 Linux 传统的进程间通信的概念和基本原理, 这样有助于我们更好的理解 Binder 的通信原理. 这个部分基本都是理论, 基础不是很好的 ...
- linux常用ipc技术,LINUX系统编程之IPC
LINUX系统编程之IPC(Inter Processes Communication) 一.信号 1.信号的产生 软件中断,异步通信,ctrl+c,kill函数,kill命令,硬件异常(段错误),软 ...
- RK1126从入门到放弃:番外篇(二)Win10 WSL系统下编译buildroot报错不支持SYSV IPC,导致fakeroot无法正常工作
Win10的Linux子系统是完全可以直接用来进行嵌入式Linux开发操作的,目前已经非常顺畅地编译通过了U-Boot和内核.但是编译Builtroot的最后阶段,需要使用fakeroot来fake文 ...
- Linux 进程间通信-IPC 机制
Linux 平台上在 Kernel 协调下完成进程之间的相互通信,有多种进程间通信 -- Inter Process Communication(IPC)方式. 1. IPC 分类 按照功能用途来看有 ...
- linux各种IPC机制
原帖发表在IBM的developerworks网站上,是一个系列的文章,作者郑彦兴,通过讲解和例子演示了Linux中几种IPC的使用方式,我觉得很好,在这里做一个保留,能看完的话Linux IPC的基 ...
最新文章
- animation动画不生效_关于CSS3的animation使用的一些坑,需要注意下!
- MyEclipse中的快捷键
- laravel mysql增删改查_Laravel框架数据库操作的增删改三种方式 阿星小栈
- 免焊vga3加6接线图_计数器和接近开关两线怎么接,计数器接近开关接线图
- win10进程太多怎么优化_用过最好用的Win10优化软件,全方面优化和管理!
- python开发环境的安装与配置_Python开发环境的安装配置
- 2016年2月23日----Javascript运算符
- linux下的僵尸进程 - Zombie
- LINQ的ORM功能中对使用sp_executesql语句的存储过程的支持
- 【C#】第2章学习要点
- Hive,Pig,HBase 傻傻分不清楚
- Android反编译实战-去广告
- 从技术问题变成RPWT -----------------猛禽
- 消息中间件MQ与RabbitMQ
- 上海迪士尼将推出虎年新春全新体验
- 查看zookeeper的版本号
- c语言API用法 查询
- pro4重影花屏 surface_【图】- 微软Surfacepro4会花屏模糊抖动怎么回事 - 厦门思明湖滨南路电脑维修 - 厦门百姓网...
- iOS-关于M1芯片可以下载APP使用问题
- 在生活之中,要活在生活之上