linux ipc system v 消息队列源码

通用数据结构
//总控结构的数据结构
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是数组下标
	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;
} 返回

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值