您的位置:首页 > 运维架构 > Linux

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;
} 返回
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: