linux SysV IPC实现
来源:互联网 发布:java md5加密 32位 编辑:程序博客网 时间:2024/06/05 15:57
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() code736 * @ns : namsepace737 * @ids : IPC identifier set738 * @ops : operations to be called on ipc object creation, permission checks739 * and further checks740 * @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 else750 return ipcget_public(ns, ids, ops, params);751 }
i.key
key类型为key_t,即int:
/usr/include/bits/types.h:101:#define__S32_TYPEint/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 set173 * @key: The key to find174 * 175 * Requires ipc_ids.rw_mutex locked.176 * Returns the LOCKED pointer to the ipc structure if found or NULL177 * if not.178 * If key is found ipc points to the owning ipc structure179 */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 object290 * @ns: namespace291 * @ids: IPC identifer set292 * @ops: the actual creation routine to call293 * @params: its parameters294 *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 one350 * @ns: namespace351 * @ids: IPC identifer set352 * @ops: the actual creation routine to call353 * @params: its parameters354 *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 permission358 * / 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 add373 * 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 else384 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 on397 * success398 */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 identifiers113 * @ids: Identifier set114 *115 * Set up the sequence range to use for the ipc identifier range (limited116 * 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 else130 ids->seq_max = seq_limit;131 }132 133 idr_init(&ids->ipcs_idr);134 }2.seq递增
236 /**237 * ipc_addid - add an IPC identifier238 * @ids: IPC identifier set239 * @new: new IPC permission set240 * @size: limit for the number of used ids241 *242 * Add an entry 'new' to the IPC ids idr. The permissions object is243 * initialised and the first free entry is set up and the id assigned244 * 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 permissions608 * @ipcp: IPC permission set609 * @flag: desired permission set.610 *611 * Check user, group, other permissions for access612 * to ipc resources. return 0 if allowed613 */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 SysV IPC sem信号量实现
- linux SysV IPC shm共享内存实现
- linux SysV IPC msg消息队列实现
- Android 不支持 SYSV IPC (SYSV IPC)
- Android 不支持 SYSV IPC (SYSV IPC)
- Linux SystemV ipc 实现
- Linux SystemV ipc 实现 .
- Linux SysV 自定义服务脚本
- Linux下IPC机制实现相关函数
- Linux 引导方式systemd upstart sysV
- Android 不支持Linux应用SYSV…
- linux IPC
- Linux IPC
- linux ipc
- linux ipc
- Linux IPC
- Linux IPC
- SurfaceView中弹出Dialog的实现
- Handling IRPs: Introduction
- Shell统计代码行数
- attrs.xml文件中属性类型format值的格式 .
- ARM920T的MMU与Cache
- linux SysV IPC实现
- jQuery学习02---jQuery对象与Dom对象
- 傅盛2
- 深入理解java多态性
- Hdu递推求解专题练习(For Beginner)
- mac ftp server
- 杭电1004
- Luhn 算法
- 种类并查集-POJ-1184