<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="http://gentoo-zh.org/extern.php?action=feed&amp;tid=423&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Gentoo中文社区 / 冬天OS（二十三）：宏内核改微内核]]></title>
		<link>http://www.gentoo-zh.org/viewtopic.php?id=423</link>
		<description><![CDATA[冬天OS（二十三）：宏内核改微内核 最近发表的帖子。]]></description>
		<lastBuildDate>Thu, 01 Sep 2022 09:01:07 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[冬天OS（二十三）：宏内核改微内核]]></title>
			<link>http://www.gentoo-zh.org/viewtopic.php?pid=429#p429</link>
			<description><![CDATA[<p>--------------------------------------------------------<br />IPC 消息机制的建立</p><p>--------------------------------------------------------</p><p>宏内核 VS 微内核<br />将内核完成的任务交给专门的任务进程来完成：例如 get_ticks 系统调用，在宏内核中 get_ticks 是作为一个系统调用函数存在的，通过系统调用函数表，内核在 ring0 执行函数 get_ticks，get_ticks 返回，这次系统调用才算结束，而在微内核中，get_ticks 不是系统调用，而是作为某个任务进程将要执行的功能函数而存在的，内核在 ring0 通过发送消息唤醒任务进程之后就立即返回！</p><p>一，建立消息通信机制</p><div class="codebox"><pre class="vscroll"><code>·sys_send 函数：
PRIVATE int msg_send(struct proc *current, int dest, MESSAGE *m)// current 是谁要发							{								// dest 是发给谁								 							// m 是要发送的消息
	struct proc *sender = current;
	struct proc *p_dest = proc_table + dest;
 
	// 确保 sender 不是给自己发
	assert(dest != proc2pid(sender));
 
	/* 确保没有死锁 */
	if (deadlock(proc2pid(sender), dest))
		panic(&quot;&gt;&gt;DEADLOCK&lt;&lt; %s-&gt;%s&quot;, sender-&gt;name, p_dest-&gt;name);
 
	if ((p_dest-&gt;p_flags &amp; RECEIVING) &amp;&amp; /* dest is waiting for the msg */
		(p_dest-&gt;p_recvfrom == proc2pid(sender) ||
		 p_dest-&gt;p_recvfrom == ANY))
	{
 
		assert(p_dest-&gt;p_msg); // p_dest-&gt;p_msg 的内存必须要开辟好
		assert(m);
 
		phys_copy(va2la(dest, p_dest-&gt;p_msg), 		// p_dest 的 msg 的线性地址同样是等于：[p_dest 的 DS : offset(p_msg)]
				  va2la(proc2pid(sender), m), 	// 内核态下所有对用户态下的数据的访问，都要基于这种形式
				  sizeof(MESSAGE));
 
		p_dest-&gt;p_msg = 0;
		p_dest-&gt;p_flags &amp;= ~RECEIVING; /* dest has received the msg */
		p_dest-&gt;p_recvfrom = NO_TASK;  // 清空 p_dest 上次是因为等待谁而阻塞！
		unblock(p_dest);
 
		assert(p_dest-&gt;p_flags == 0);
		assert(p_dest-&gt;p_msg == 0);
		assert(p_dest-&gt;p_recvfrom == NO_TASK);
		assert(p_dest-&gt;p_sendto == NO_TASK);
		assert(sender-&gt;p_flags == 0);
		assert(sender-&gt;p_msg == 0);
		assert(sender-&gt;p_recvfrom == NO_TASK);
		assert(sender-&gt;p_sendto == NO_TASK);
	}
	else
	{ 	/* dest is not waiting for the msg */
		sender-&gt;p_flags |= SENDING;
		assert(sender-&gt;p_flags == SENDING);
		sender-&gt;p_sendto = dest;
		sender-&gt;p_msg = m; // m 其实就是 sender 要发送给 dest 的包，
				   // 只是这里在构建 sender 的阻塞状态的时候需要让 p_msg 指向 m
 
		/* append to the sending queue */
		struct proc *p;
		if (p_dest-&gt;q_sending)
		{
			p = p_dest-&gt;q_sending;
			while (p-&gt;next_sending)
				p = p-&gt;next_sending;
			p-&gt;next_sending = sender;
		}
		else
			p_dest-&gt;q_sending = sender;
		sender-&gt;next_sending = 0;
 
		block(sender); // 把控制权交给别人，等同于自己同时阻塞
 
		assert(sender-&gt;p_flags == SENDING);
		assert(sender-&gt;p_msg != 0);
		assert(sender-&gt;p_recvfrom == NO_TASK);
		assert(sender-&gt;p_sendto == dest);
	}
 
	return 0;
}</code></pre></div><p> ——sys_send 首先简单地检查是否产生死锁，然后检查如果 recv 方正在 recving 并且 want recv 就是自己（或者 any），就将消息赋值给 recv 方，然后唤醒对方！否则 recv 方没打算接收或者想接收的不是自己，就进行阻塞前的准备设置然后阻塞！</p><div class="codebox"><pre class="vscroll"><code>·sys_receive 函数：
PRIVATE int msg_receive(struct proc *current, int src, MESSAGE *m) // m：将消息往回收到 m 中
{																   // sec：从哪里收
																   // current：谁想回收
	struct proc *p_who_wanna_recv = current;					  
	struct proc *p_from = 0;									   /* from which the message will be fetched */
	struct proc *prev = 0;
	int copyok = 0;
 
	assert(proc2pid(p_who_wanna_recv) != src); // 不能从自己接收
 
	if ((p_who_wanna_recv-&gt;has_int_msg) &amp;&amp;
		((src == ANY) || (src == INTERRUPT)))
	{
		/* There is an interrupt needs p_who_wanna_recv&#039;s handling and
		 * p_who_wanna_recv is ready to handle it.
		 */
 
		MESSAGE msg;
		reset_msg(&amp;msg);
		msg.source = INTERRUPT;
		msg.type = HARD_INT;
 
		assert(m);
 
		// 代表着接收到了中断消息，然后满载而归！
		// 注意这里并没有随之唤醒“中断进程”，因为中断不会阻塞着等待接收进程接收！
		phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &amp;msg,
				  sizeof(MESSAGE));
 
		p_who_wanna_recv-&gt;has_int_msg = 0;
 
		assert(p_who_wanna_recv-&gt;p_flags == 0);
		assert(p_who_wanna_recv-&gt;p_msg == 0);
		assert(p_who_wanna_recv-&gt;p_sendto == NO_TASK);
		assert(p_who_wanna_recv-&gt;has_int_msg == 0);
 
		return 0;
	}
 
	/* Arrives here if no interrupt for p_who_wanna_recv. */
	if (src == ANY)
	{
		/* p_who_wanna_recv is ready to receive messages from
		 * ANY proc, we&#039;ll check the sending queue and pick the
		 * first proc in it.
		 */
		if (p_who_wanna_recv-&gt;q_sending)
		{
			// p_frome 就是 p_who_wanna_recv 等待队列上的第一个
			p_from = p_who_wanna_recv-&gt;q_sending;
			copyok = 1;
 
			assert(p_who_wanna_recv-&gt;p_flags == 0);
			assert(p_who_wanna_recv-&gt;p_msg == 0);
			assert(p_who_wanna_recv-&gt;p_recvfrom == NO_TASK);
			assert(p_who_wanna_recv-&gt;p_sendto == NO_TASK);
			assert(p_who_wanna_recv-&gt;q_sending != 0);
			assert(p_from-&gt;p_flags == SENDING);
			assert(p_from-&gt;p_msg != 0);
			assert(p_from-&gt;p_recvfrom == NO_TASK);
			assert(p_from-&gt;p_sendto == proc2pid(p_who_wanna_recv));
		}
	}
	else if (src &gt;= 0 &amp;&amp; src &lt; NR_TASKS + NR_PROCS)
	{
		/* p_who_wanna_recv wants to receive a message from
		 * a certain proc: src.
		 */
 
		// 接收者就想接收指定进程的消息，那么开始判断指定进程是否在发送消息并且在给自己发送消息
		// 之后把他的数据接受了并把它唤醒，然后从自己的发送阻塞队列上剔除！
		p_from = &amp;proc_table[src];
		if ((p_from-&gt;p_flags &amp; SENDING) &amp;&amp;
			(p_from-&gt;p_sendto == proc2pid(p_who_wanna_recv)))
		{
			/* Perfect, src is sending a message to
			 * p_who_wanna_recv.
			 */
			copyok = 1;
 
			struct proc *p = p_who_wanna_recv-&gt;q_sending;
 
			assert(p); /* p_from must have been appended to the
				    * queue, so the queue must not be NULL
				    */
 
			// 这里在 p_who_wanna_recv 的 q_sending 队列上找到那个具体的进程
			// 估计要做更新等待列表的工作
			while (p)
			{
				assert(p_from-&gt;p_flags &amp; SENDING);
 
				if (proc2pid(p) == src) /* if p is the one */
					break;
 
				prev = p;
				p = p-&gt;next_sending;
			}
 
			assert(p_who_wanna_recv-&gt;p_flags == 0);
			assert(p_who_wanna_recv-&gt;p_msg == 0);
			assert(p_who_wanna_recv-&gt;p_recvfrom == NO_TASK);
			assert(p_who_wanna_recv-&gt;p_sendto == NO_TASK);
			assert(p_who_wanna_recv-&gt;q_sending != 0);
			assert(p_from-&gt;p_flags == SENDING);
			assert(p_from-&gt;p_msg != 0);
			assert(p_from-&gt;p_recvfrom == NO_TASK);
			assert(p_from-&gt;p_sendto == proc2pid(p_who_wanna_recv));
		}
	}
 
	if (copyok)
	{
		/* It&#039;s determined from which proc the message will
		 * be copied. Note that this proc must have been
		 * waiting for this moment in the queue, so we should
		 * remove it from the queue.
		 */
		// update the queue！
		if (p_from == p_who_wanna_recv-&gt;q_sending)
		{ /* the 1st one */
			assert(prev == 0);
			p_who_wanna_recv-&gt;q_sending = p_from-&gt;next_sending;
			p_from-&gt;next_sending = 0;
		}
		else
		{
			assert(prev);
			prev-&gt;next_sending = p_from-&gt;next_sending;
			p_from-&gt;next_sending = 0;
		}
 
		assert(m);
		assert(p_from-&gt;p_msg);
 
		/* copy the message */
		phys_copy(va2la(proc2pid(p_who_wanna_recv), m),
				  va2la(proc2pid(p_from), p_from-&gt;p_msg),
				  sizeof(MESSAGE));
 
		p_from-&gt;p_msg = 0;
		p_from-&gt;p_sendto = NO_TASK;
		p_from-&gt;p_flags &amp;= ~SENDING;
 
		// 将发送方解锁掉，下一次就会加入调度
		unblock(p_from);
	}
	else
	{ /* nobody&#039;s sending any msg */
		/* Set p_flags so that p_who_wanna_recv will not
		 * be scheduled until it is unblocked.
		 */
		p_who_wanna_recv-&gt;p_flags |= RECEIVING;
		p_who_wanna_recv-&gt;p_msg = m;
		p_who_wanna_recv-&gt;p_recvfrom = src; // recv 方阻塞自己的时候指明它原本是想从哪里接收数据！
		block(p_who_wanna_recv);
 
		assert(p_who_wanna_recv-&gt;p_flags == RECEIVING);
		assert(p_who_wanna_recv-&gt;p_msg != 0);
		assert(p_who_wanna_recv-&gt;p_recvfrom != NO_TASK);
		assert(p_who_wanna_recv-&gt;p_sendto == NO_TASK);
		assert(p_who_wanna_recv-&gt;has_int_msg == 0);
	}
 
	return 0;
}</code></pre></div><p>——msg_recv 首先检查是否有中断通知，如果有，就“接受”中断通知然后返回，如果没有中断通知，就判断 recv 是想从 any 接收还是从具体的进程接收，从 any 接收好办，选择 recv 的发送队列的第一个 send 然后接收他的消息就行了，如果是从具体进程 recv ，那么就要判断那个具体的进程是否正在给 recv 发送，如果正在，那么一拍即合（否则就 recv 就会阻塞的），拿走那个 send 的数据然后激活 send ，自己返回！</p><p> </p><p>测试消息机制：<br />开始 TestA 阻塞在从 TestB 接收数据，并且 TestC 阻塞在想从 ANY 接收数据，然后 TestB 发消息给 TestA，TestA 接收到 TestB 的消息了之后又给 TestC 发送消息！</p><p>二，宏内核改微内核<br />消息机制是微内核的核心，我们既然已经有了消息机制，就可以搭建微内核了，上面消息机制的测试中，TestX 都是发送或者接收了一次消息之后就不再发送或者接收消息了，如果我们弄一个进程，在那里不间断地 recv ，再给 MESSAGE 注明类型，我们就可以说：哪个进程给哪个系统任务发送了消息，请求的是这个系统任务的哪种类型的服务！（服务的类型取决于系统任务支持什么类型的服务，不能你虽然把我唤醒了，但请求的不是我力所能及的服务，可以猜猜 sys_server 会做什么反应 <img src="http://www.gentoo-zh.org/img/smilies/smile.png" width="15" height="15" alt="smile" />）</p><p>1，添加一个系统任务：sys_server<br />2，增加 sys_server 提供的一种服务类型（GET_TICKS）<br />3，TestB 和 TestC 之间互相传递消息</p><div class="codebox"><pre class="vscroll"><code>·main.c 节选
PUBLIC int get_ticks()
{
	MESSAGE msg;
	reset_msg(&amp;msg);
	msg.type = GET_TICKS;
	send_recv(BOTH, TASK_SERVER, &amp;msg);
	return msg.RETVAL;
}
 
void TestA()
{
	while (TRUE)
	{
		printf(&quot;%d  &quot;, get_ticks());
		milli_delay(300);
	}
}
 
void TestB()
{
	MESSAGE _m;
	_m.RETVAL = 1;
	while (TRUE)
	{
		send_recv(SEND, 4, &amp;_m);
		send_recv(RECEIVE, 4, &amp;_m);
		printf(&quot;TestB number is [%d]\n&quot;, ++_m.RETVAL);
		milli_delay(2000);
	}
}
 
void TestC()
{
	MESSAGE _m;
	while (TRUE)
	{
		send_recv(RECEIVE, 3, &amp;_m);
		printf(&quot;TestC number is [%d]\n&quot;, ++_m.RETVAL);
		send_recv(SEND, 3, &amp;_m);
	}
}</code></pre></div><div class="codebox"><pre class="vscroll"><code>·sys_task.c
// ----------------------------
// &lt;systask.c&gt;
//                      Jack Zheng
//              Comment:December 7, 2019
// ----------------------------
#include &quot;type.h&quot;
#include &quot;const.h&quot;
#include &quot;protect.h&quot;
#include &quot;string.h&quot;
#include &quot;proc.h&quot;
#include &quot;tty.h&quot;
#include &quot;console.h&quot;
#include &quot;global.h&quot;
#include &quot;keyboard.h&quot;
#include &quot;proto.h&quot;
 
void task_server()
{
 
    MESSAGE _m;
    while (TRUE)
    {
        send_recv(RECEIVE, ANY, &amp;_m);
        int src = _m.source;
        switch (_m.type)
        {
        case GET_TICKS: /* 某个进程请求的这个服务 */
            _m.RETVAL = ticks;
            send_recv(SEND, src, &amp;_m);
            break;
 
        default:
            panic(&quot;unknown Message type&quot;);
            break;
        }
    }
}</code></pre></div>]]></description>
			<author><![CDATA[dummy@example.com (batsom)]]></author>
			<pubDate>Thu, 01 Sep 2022 09:01:07 +0000</pubDate>
			<guid>http://www.gentoo-zh.org/viewtopic.php?pid=429#p429</guid>
		</item>
	</channel>
</rss>
