linux ipc system v 消息队列源码
2013-09-23 08:37
288 查看
通用数据结构 //总控结构的数据结构 struct ipc_ids { int size; /*队列数组的容量 int in_use; /*使用中的队列数 int max_id; /*队列数组的最大不为空下标 unsigned short seq; /*序列号 unsigned short seq_max; /*最大序列号 struct semaphore sem; /*用于控制进程间互斥的信号量 spinlock_t ary; /*用于防止多个CPU同时操作的锁 struct ipc_id* entries; /*队列数组的入口 }; //信号量的数据结构 struct semaphore { atomic_t count; // int sleepers; //在该信号量上面睡眠的进程数 wait_queue_head_t wait; //等待的队列 #if WAITQUEUE_DEBUG long __magic; //模数 #endif }; struct ipc_id { struct kern_ipc_perm* p; }; //权限控制信息数据结构 struct kern_ipc_perm { key_t key; //关键字 //对象拥有者对应进程的有效用户识别号和有效组识别号 uid_t uid; gid_t gid; //对象创建者对应进程的有效用户识别号和有效组识别号 uid_t cuid; gid_t cgid; mode_t mode; //存取模式 unsigned long seq; // 序列号 }; 通用函数 1.初始化 start_kernel(void) ipc_init (void) sem_init(); msg_init(); shm_init(); ipc_init_ids(struct ipc_ids* ids, int size) 2.创建/取得队列 ——返回队列标识号 newque (key_t key, int msgflg) newary (key_t key, int nsems, int semflg) shm_addid(struct shmid_kernel *shp) ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) //队列加入总控结构 grow_ary(struct ipc_ids* ids, int newsize) //增加总控结构的队列数 初始化三种队列中其他成员 int ipc_buildid(struct ipc_ids* ids, int id, int seq) //生成队列标识号 增加一个队列时 ipc_ids.seq++ 并且所增加的队列的kern_ipc_perm.seq = ipc_ids.seq 但在删除该队列时 ipc_ids.seq 并不减小 这就保证了SEQ_MULTIPLIER*seq + id 的唯一性 当消息调用者引用一个队列之后,原先处于那个下标的队列可能已经别删除了,而且在同一个下标出创建了一个新的队列,但旧队列和新队列的标号不同,这样避免了错误操作队列的可能性。 3.查找队列 long sys_msgget (key_t key, int msgflg) long sys_semget (key_t key, int nsems, int semflg) long sys_shmget (key_t key, size_t size, int shmflg) ipc_findkey(struct ipc_ids* ids, key_t key) //根据系统调用参数传递过来的key来查找队列 kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id) //根据队列标识号返回队列的下标 (只在共享内存中使用) kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id) //根据队列标识号返回队列的的kern_ipc_perm结构指针 int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) //根据队列标识号检查队列的序号 4.队列访问控制 kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id) //根据队列标识号返回队列的下标, 并对总控结构上锁 spin_lock(&ids->ary); //上锁 extern inline void ipc_unlock(struct ipc_ids* ids, int id) { spin_unlock(&ids->ary); } //在对三种队列的操作之前,都会对取得的队列进行访问权限检查。 ipcperms (struct kern_ipc_perm *ipcp, short flag) //对进程的 IPC 访问权限进行检查 extern inline int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) { if(uid/SEQ_MULTIPLIER != ipcp->seq) return 1; return 0; } 5.删除队列 kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id) //删除数组中下标为id % SEQ_MULTIPLIER的队列 代码部分: void __init ipc_init_ids(struct ipc_ids* ids, int size) { int i; sema_init(&ids->sem,1); //信号量初始化 if(size > IPCMNI) size = IPCMNI; ids->size = size; ids->in_use = 0; ids->max_id = -1; ids->seq = 0; { //设置最大序列号 int seq_limit = INT_MAX/SEQ_MULTIPLIER; /*#define IPCMNI 32768 / * #define INT_MAX ((int)(~0U>>1)) ? / *#define SEQ_MULTIPLIER (IPCMNI) if(seq_limit > USHRT_MAX) ids->seq_max = USHRT_MAX; /*#define USHRT_MAX 0xffff else ids->seq_max = seq_limit; } ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);//分配空间 if(ids->entries == NULL) { printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n"); ids->size = 0; } ids->ary = SPIN_LOCK_UNLOCKED; for(i=0;i<ids->size;i++) ids->entries[i].p = NULL; } 返回 extern inline struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id) { //根据队列标识号返回队列的kern_ipc_perm结构指针 struct kern_ipc_perm* out; int lid = id % SEQ_MULTIPLIER; // SEQ_MULTIPLIER=队列数组的最大维数32768 if(lid >= ids->size) return NULL; spin_lock(&ids->ary); //上锁 out = ids->entries[lid].p; if(out==NULL) spin_unlock(&ids->ary); //如果队列已经为空,则解锁 return out; } 返回 int ipcperms (struct kern_ipc_perm *ipcp, short flag) { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ int requested_mode, granted_mode; requested_mode = (flag >> 6) | (flag >> 3) | flag; granted_mode = ipcp->mode; if (current->euid == ipcp->cuid || current->euid == ipcp->uid) granted_mode >>= 6; else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) granted_mode >>= 3; /* is there some bit set in requested_mode but not in granted_mode? */ if ((requested_mode & ~granted_mode & 0007) && !capable(CAP_IPC_OWNER)) return -1; return 0; } 返回 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) { //找到一个空位置然后加入 int id; size = grow_ary(ids,size); //按照新的标准扩大队列数组的容量 for (id = 0; id < size; id++) { if(ids->entries[id].p == NULL) //找到一个空位置 goto found; } return -1; found: ids->in_use++; if (id > ids->max_id) ids->max_id = id; new->cuid = new->uid = current->euid; new->gid = new->cgid = current->egid; new->seq = ids->seq++; //序号增加,直到为最大时,再重新从0开始 if(ids->seq > ids->seq_max) ids->seq = 0; spin_lock(&ids->ary); //联入新的队列之前先锁队列 ids->entries[id].p = new; return id; } 返回 static int grow_ary(struct ipc_ids* ids, int newsize) { struct ipc_id* new; struct ipc_id* old; int i; if(newsize > IPCMNI) newsize = IPCMNI; if(newsize <= ids->size) return newsize; new = ipc_alloc(sizeof(struct ipc_id)*newsize); if(new == NULL) return ids->size; memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size); for(i=ids->size;i<newsize;i++) { new[i].p = NULL; } spin_lock(&ids->ary); old = ids->entries; ids->entries = new; i = ids->size; ids->size = newsize; spin_unlock(&ids->ary); ipc_free(old, sizeof(struct ipc_id)*i); return ids->size; } 返回 extern inline int ipc_buildid(struct ipc_ids* ids, int id, int seq) { return SEQ_MULTIPLIER*seq + id; } 返回 extern inline int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) { if(uid/SEQ_MULTIPLIER != ipcp->seq) return 1; return 0; } 返回 extern inline struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id) { struct kern_ipc_perm* out; int lid = id % SEQ_MULTIPLIER; if(lid >= ids->size) return NULL; spin_lock(&ids->ary); out = ids->entries[lid].p; if(out==NULL) spin_unlock(&ids->ary); return out; } 返回 static inline void spin_lock(spinlock_t *lock) { #if SPINLOCK_DEBUG __label__ here; here: if (lock->magic != SPINLOCK_MAGIC) { printk("eip: %p\n", &&here); BUG(); } #endif __asm__ __volatile__( spin_lock_string :"=m" (lock->lock) : : "memory"); // } 返回 typedef struct { volatile unsigned int lock; #if SPINLOCK_DEBUG unsigned magic; #endif } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT } #define spin_lock_string \ "\n1:\t" \ "lock ; decb %0\n\t" \ "js 2f\n" \ ".subsection 1\n" \ ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ ".endif\n" \ "2:\t" \ "cmpb $0,%0\n\t" \ "rep;nop\n\t" \ "jle 2b\n\t" \ "jmp 1b\n" \ ".subsection 0\n" extern inline void ipc_unlock(struct ipc_ids* ids, int id) { spin_unlock(&ids->ary); } 返回 struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id) { struct kern_ipc_perm* p; int lid = id % SEQ_MULTIPLIER; //id是计算出来的唯一标志,lid是数组 4000 下标 if(lid >= ids->size) BUG(); p = ids->entries[lid].p; ids->entries[lid].p = NULL; if(p==NULL) BUG(); ids->in_use--; if (lid == ids->max_id) { //如果删除的是下标最大的那个队列,则找到删除后下标最大且不为空的队列的下标跟新总控结构ipc_ids.max_id do { lid--; if(lid == -1) break; } while (ids->entries[lid].p == NULL); ids->max_id = lid; } return p; } 返回
相关文章推荐
- linux基础编程:进程通信之System V IPC:消息队列,信号量,共享内存
- linux基础编程:进程通信之System V IPC:消息队列,信号量,共享内存
- [linux系统编程]System V IPC 消息队列
- Linux systemV 消息队列 IPC及Stack smashing detected解决方案
- linux—进程通信IPC--system v-消息队列
- 细说linux IPC(十):system V 消息队列
- System V IPC & POSIX IPC(一):消息队列
- Linux 进程间通信 (IPC) // 消息队列
- Linux进程通信IPC--消息队列MessageQueue
- Linux进程间通信(IPC)编程实践(十二)Posix消息队列--基本API的使用
- linux网络编程之System V 消息队列(一):消息队列内核结构和msgget、msgctl 函数
- [Linux管道和IPC]使用msgctl删除消息队列
- ipc消息队列系统函数调用源码入口:如sys_msgsnd
- Unix/Linux进程间通信——(System V)消息队列
- Linux — IPC进程通信之消息队列详解
- Linux 进程通信(System V)消息队列
- Linux IPC实践(4) --System V消息队列(1)
- [Linux管道和IPC]消息队列发送客户端
- Linux IPC实践(4) --System V消息队列(1)
- 【Linux/OS/Network】XSI IPC(消息队列,信号量,共享内存)