<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="https://www.gentoo-zh.org/extern.php?action=feed&amp;tid=822&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Gentoo中文社区 / Gentoo 之 system v 消息队列源码]]></title>
		<link>https://www.gentoo-zh.org/viewtopic.php?id=822</link>
		<description><![CDATA[Gentoo 之 system v 消息队列源码 最近发表的帖子。]]></description>
		<lastBuildDate>Fri, 01 Mar 2024 04:47:50 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Gentoo 之 system v 消息队列源码]]></title>
			<link>https://www.gentoo-zh.org/viewtopic.php?pid=938#p938</link>
			<description><![CDATA[<div class="codebox"><pre class="vscroll"><code> 通用数据结构
//总控结构的数据结构
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(&amp;ids-&gt;ary);        //上锁
extern inline void ipc_unlock(struct ipc_ids* ids, int id)
{
	spin_unlock(&amp;ids-&gt;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-&gt;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(&amp;ids-&gt;sem,1);   //信号量初始化
	if(size &gt; IPCMNI)
		size = IPCMNI;
	ids-&gt;size = size;
	ids-&gt;in_use = 0;
	ids-&gt;max_id = -1;
	ids-&gt;seq = 0;
	{  //设置最大序列号
		int seq_limit = INT_MAX/SEQ_MULTIPLIER;   
 /*#define IPCMNI 32768  
 / * #define INT_MAX		((int)(~0U&gt;&gt;1))  ？
/ *#define SEQ_MULTIPLIER	(IPCMNI)
		if(seq_limit &gt; USHRT_MAX)
			ids-&gt;seq_max = USHRT_MAX;
              /*#define USHRT_MAX  0xffff
		 else
		 	ids-&gt;seq_max = seq_limit;
	}
	ids-&gt;entries = ipc_alloc(sizeof(struct ipc_id)*size);//分配空间
	if(ids-&gt;entries == NULL) {
		printk(KERN_ERR &quot;ipc_init_ids() failed, ipc service disabled.\n&quot;);
		ids-&gt;size = 0;
	}
	ids-&gt;ary = SPIN_LOCK_UNLOCKED;
	for(i=0;i&lt;ids-&gt;size;i++)
		ids-&gt;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 &gt;= ids-&gt;size)
		return NULL;
	spin_lock(&amp;ids-&gt;ary);        //上锁
	out = ids-&gt;entries[lid].p;
	if(out==NULL)
		spin_unlock(&amp;ids-&gt;ary);   //如果队列已经为空，则解锁
	return out;
}  返回
int ipcperms (struct kern_ipc_perm *ipcp, short flag)
{	/* flag will most probably be 0 or S_...UGO from &lt;linux/stat.h&gt; */
	int requested_mode, granted_mode;
	requested_mode = (flag &gt;&gt; 6) | (flag &gt;&gt; 3) | flag;
	granted_mode = ipcp-&gt;mode;
	if (current-&gt;euid == ipcp-&gt;cuid || current-&gt;euid == ipcp-&gt;uid)
		granted_mode &gt;&gt;= 6;
	else if (in_group_p(ipcp-&gt;cgid) || in_group_p(ipcp-&gt;gid))
		granted_mode &gt;&gt;= 3;
	/* is there some bit set in requested_mode but not in granted_mode? */
	if ((requested_mode &amp; ~granted_mode &amp; 0007) &amp;&amp; 
	    !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 &lt; size; id++) {
		if(ids-&gt;entries[id].p == NULL)     //找到一个空位置
			goto found;
	}
	return -1;
found:
	ids-&gt;in_use++;
	if (id &gt; ids-&gt;max_id)
		ids-&gt;max_id = id;
 
	new-&gt;cuid = new-&gt;uid = current-&gt;euid;
	new-&gt;gid = new-&gt;cgid = current-&gt;egid;
 
	new-&gt;seq = ids-&gt;seq++;               //序号增加，直到为最大时，再重新从0开始
	if(ids-&gt;seq &gt; ids-&gt;seq_max)
		ids-&gt;seq = 0;
 
	spin_lock(&amp;ids-&gt;ary);           //联入新的队列之前先锁队列
	ids-&gt;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 &gt; IPCMNI)
		newsize = IPCMNI;
	if(newsize &lt;= ids-&gt;size)    
		return newsize;
 
	new = ipc_alloc(sizeof(struct ipc_id)*newsize);
	if(new == NULL)
		return ids-&gt;size;
	memcpy(new, ids-&gt;entries, sizeof(struct ipc_id)*ids-&gt;size);
	for(i=ids-&gt;size;i&lt;newsize;i++) {
		new[i].p = NULL;
	}
	spin_lock(&amp;ids-&gt;ary);
 
	old = ids-&gt;entries;
	ids-&gt;entries = new;
	i = ids-&gt;size;
	ids-&gt;size = newsize;
	spin_unlock(&amp;ids-&gt;ary);
	ipc_free(old, sizeof(struct ipc_id)*i);
	return ids-&gt;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-&gt;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 &gt;= ids-&gt;size)
		return NULL;
 
	spin_lock(&amp;ids-&gt;ary);
	out = ids-&gt;entries[lid].p;
	if(out==NULL)
		spin_unlock(&amp;ids-&gt;ary);
	return out;
} 返回
 
static inline void spin_lock(spinlock_t *lock)
{
#if SPINLOCK_DEBUG
	__label__ here;
here:
	if (lock-&gt;magic != SPINLOCK_MAGIC) {
printk(&quot;eip: %p\n&quot;, &amp;&amp;here);
		BUG();
	}
#endif
	__asm__ __volatile__(
		spin_lock_string
		:&quot;=m&quot; (lock-&gt;lock) : : &quot;memory&quot;);     // 
} 返回
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 \
	&quot;\n1:\t&quot; \
	&quot;lock ; decb %0\n\t&quot; \
	&quot;js 2f\n&quot; \
	&quot;.subsection 1\n&quot; \
	&quot;.ifndef _text_lock_&quot; __stringify(KBUILD_BASENAME) &quot;\n&quot; \
	&quot;_text_lock_&quot; __stringify(KBUILD_BASENAME) &quot;:\n&quot; \
	&quot;.endif\n&quot; \
	&quot;2:\t&quot; \
	&quot;cmpb $0,%0\n\t&quot; \
	&quot;rep;nop\n\t&quot; \
	&quot;jle 2b\n\t&quot; \
	&quot;jmp 1b\n&quot; \
	&quot;.subsection 0\n&quot;
extern inline void ipc_unlock(struct ipc_ids* ids, int id)
{
	spin_unlock(&amp;ids-&gt;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 &gt;= ids-&gt;size)
		BUG();
	p = ids-&gt;entries[lid].p;
	ids-&gt;entries[lid].p = NULL;
	if(p==NULL)
		BUG();
	ids-&gt;in_use--;
 
	if (lid == ids-&gt;max_id) {             
//如果删除的是下标最大的那个队列，则找到删除后下标最大且不为空的队列的下标跟新总控结构ipc_ids.max_id
		do {
			lid--;
			if(lid == -1)
				break;
		} while (ids-&gt;entries[lid].p == NULL);
		ids-&gt;max_id = lid;
	}
	return p;
} 返回 </code></pre></div>]]></description>
			<author><![CDATA[dummy@example.com (batsom)]]></author>
			<pubDate>Fri, 01 Mar 2024 04:47:50 +0000</pubDate>
			<guid>https://www.gentoo-zh.org/viewtopic.php?pid=938#p938</guid>
		</item>
	</channel>
</rss>
