赞
踩
--------------------------------------------------------
--------------------------------------------------------
宏内核 VS 微内核
将内核完成的任务交给专门的任务进程来完成:例如 get_ticks 系统调用,在宏内核中 get_ticks 是作为一个系统调用函数存在的,通过系统调用函数表,内核在 ring0 执行函数 get_ticks,get_ticks 返回,这次系统调用才算结束,而在微内核中,get_ticks 不是系统调用,而是作为某个任务进程将要执行的功能函数而存在的,内核在 ring0 通过发送消息唤醒任务进程之后就立即返回!
一,建立消息通信机制
- ·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(">>DEADLOCK<< %s->%s", sender->name, p_dest->name);
-
- if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */
- (p_dest->p_recvfrom == proc2pid(sender) ||
- p_dest->p_recvfrom == ANY))
- {
-
- assert(p_dest->p_msg); // p_dest->p_msg 的内存必须要开辟好
- assert(m);
-
- phys_copy(va2la(dest, p_dest->p_msg), // p_dest 的 msg 的线性地址同样是等于:[p_dest 的 DS : offset(p_msg)]
- va2la(proc2pid(sender), m), // 内核态下所有对用户态下的数据的访问,都要基于这种形式
- sizeof(MESSAGE));
-
- p_dest->p_msg = 0;
- p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */
- p_dest->p_recvfrom = NO_TASK; // 清空 p_dest 上次是因为等待谁而阻塞!
- unblock(p_dest);
-
- assert(p_dest->p_flags == 0);
- assert(p_dest->p_msg == 0);
- assert(p_dest->p_recvfrom == NO_TASK);
- assert(p_dest->p_sendto == NO_TASK);
- assert(sender->p_flags == 0);
- assert(sender->p_msg == 0);
- assert(sender->p_recvfrom == NO_TASK);
- assert(sender->p_sendto == NO_TASK);
- }
- else
- { /* dest is not waiting for the msg */
- sender->p_flags |= SENDING;
- assert(sender->p_flags == SENDING);
- sender->p_sendto = dest;
- sender->p_msg = m; // m 其实就是 sender 要发送给 dest 的包,
- // 只是这里在构建 sender 的阻塞状态的时候需要让 p_msg 指向 m
-
- /* append to the sending queue */
- struct proc *p;
- if (p_dest->q_sending)
- {
- p = p_dest->q_sending;
- while (p->next_sending)
- p = p->next_sending;
- p->next_sending = sender;
- }
- else
- p_dest->q_sending = sender;
- sender->next_sending = 0;
-
- block(sender); // 把控制权交给别人,等同于自己同时阻塞
-
- assert(sender->p_flags == SENDING);
- assert(sender->p_msg != 0);
- assert(sender->p_recvfrom == NO_TASK);
- assert(sender->p_sendto == dest);
- }
-
- return 0;
- }
——sys_send 首先简单地检查是否产生死锁,然后检查如果 recv 方正在 recving 并且 want recv 就是自己(或者 any),就将消息赋值给 recv 方,然后唤醒对方!否则 recv 方没打算接收或者想接收的不是自己,就进行阻塞前的准备设置然后阻塞!
- ·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->has_int_msg) &&
- ((src == ANY) || (src == INTERRUPT)))
- {
- /* There is an interrupt needs p_who_wanna_recv's handling and
- * p_who_wanna_recv is ready to handle it.
- */
-
- MESSAGE msg;
- reset_msg(&msg);
- msg.source = INTERRUPT;
- msg.type = HARD_INT;
-
- assert(m);
-
- // 代表着接收到了中断消息,然后满载而归!
- // 注意这里并没有随之唤醒“中断进程”,因为中断不会阻塞着等待接收进程接收!
- phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg,
- sizeof(MESSAGE));
-
- p_who_wanna_recv->has_int_msg = 0;
-
- assert(p_who_wanna_recv->p_flags == 0);
- assert(p_who_wanna_recv->p_msg == 0);
- assert(p_who_wanna_recv->p_sendto == NO_TASK);
- assert(p_who_wanna_recv->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'll check the sending queue and pick the
- * first proc in it.
- */
- if (p_who_wanna_recv->q_sending)
- {
- // p_frome 就是 p_who_wanna_recv 等待队列上的第一个
- p_from = p_who_wanna_recv->q_sending;
- copyok = 1;
-
- assert(p_who_wanna_recv->p_flags == 0);
- assert(p_who_wanna_recv->p_msg == 0);
- assert(p_who_wanna_recv->p_recvfrom == NO_TASK);
- assert(p_who_wanna_recv->p_sendto == NO_TASK);
- assert(p_who_wanna_recv->q_sending != 0);
- assert(p_from->p_flags == SENDING);
- assert(p_from->p_msg != 0);
- assert(p_from->p_recvfrom == NO_TASK);
- assert(p_from->p_sendto == proc2pid(p_who_wanna_recv));
- }
- }
- else if (src >= 0 && src < NR_TASKS + NR_PROCS)
- {
- /* p_who_wanna_recv wants to receive a message from
- * a certain proc: src.
- */
-
- // 接收者就想接收指定进程的消息,那么开始判断指定进程是否在发送消息并且在给自己发送消息
- // 之后把他的数据接受了并把它唤醒,然后从自己的发送阻塞队列上剔除!
- p_from = &proc_table[src];
- if ((p_from->p_flags & SENDING) &&
- (p_from->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->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->p_flags & SENDING);
-
- if (proc2pid(p) == src) /* if p is the one */
- break;
-
- prev = p;
- p = p->next_sending;
- }
-
- assert(p_who_wanna_recv->p_flags == 0);
- assert(p_who_wanna_recv->p_msg == 0);
- assert(p_who_wanna_recv->p_recvfrom == NO_TASK);
- assert(p_who_wanna_recv->p_sendto == NO_TASK);
- assert(p_who_wanna_recv->q_sending != 0);
- assert(p_from->p_flags == SENDING);
- assert(p_from->p_msg != 0);
- assert(p_from->p_recvfrom == NO_TASK);
- assert(p_from->p_sendto == proc2pid(p_who_wanna_recv));
- }
- }
-
- if (copyok)
- {
- /* It'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->q_sending)
- { /* the 1st one */
- assert(prev == 0);
- p_who_wanna_recv->q_sending = p_from->next_sending;
- p_from->next_sending = 0;
- }
- else
- {
- assert(prev);
- prev->next_sending = p_from->next_sending;
- p_from->next_sending = 0;
- }
-
- assert(m);
- assert(p_from->p_msg);
-
- /* copy the message */
- phys_copy(va2la(proc2pid(p_who_wanna_recv), m),
- va2la(proc2pid(p_from), p_from->p_msg),
- sizeof(MESSAGE));
-
- p_from->p_msg = 0;
- p_from->p_sendto = NO_TASK;
- p_from->p_flags &= ~SENDING;
-
- // 将发送方解锁掉,下一次就会加入调度
- unblock(p_from);
- }
- else
- { /* nobody'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->p_flags |= RECEIVING;
- p_who_wanna_recv->p_msg = m;
- p_who_wanna_recv->p_recvfrom = src; // recv 方阻塞自己的时候指明它原本是想从哪里接收数据!
- block(p_who_wanna_recv);
-
- assert(p_who_wanna_recv->p_flags == RECEIVING);
- assert(p_who_wanna_recv->p_msg != 0);
- assert(p_who_wanna_recv->p_recvfrom != NO_TASK);
- assert(p_who_wanna_recv->p_sendto == NO_TASK);
- assert(p_who_wanna_recv->has_int_msg == 0);
- }
-
- return 0;
- }
——msg_recv 首先检查是否有中断通知,如果有,就“接受”中断通知然后返回,如果没有中断通知,就判断 recv 是想从 any 接收还是从具体的进程接收,从 any 接收好办,选择 recv 的发送队列的第一个 send 然后接收他的消息就行了,如果是从具体进程 recv ,那么就要判断那个具体的进程是否正在给 recv 发送,如果正在,那么一拍即合(否则就 recv 就会阻塞的),拿走那个 send 的数据然后激活 send ,自己返回!
测试消息机制:
开始 TestA 阻塞在从 TestB 接收数据,并且 TestC 阻塞在想从 ANY 接收数据,然后 TestB 发消息给 TestA,TestA 接收到 TestB 的消息了之后又给 TestC 发送消息!
二,宏内核改微内核
消息机制是微内核的核心,我们既然已经有了消息机制,就可以搭建微内核了,上面消息机制的测试中,TestX 都是发送或者接收了一次消息之后就不再发送或者接收消息了,如果我们弄一个进程,在那里不间断地 recv ,再给 MESSAGE 注明类型,我们就可以说:哪个进程给哪个系统任务发送了消息,请求的是这个系统任务的哪种类型的服务!(服务的类型取决于系统任务支持什么类型的服务,不能你虽然把我唤醒了,但请求的不是我力所能及的服务,可以猜猜 sys_server 会做什么反应 :))
1,添加一个系统任务:sys_server
2,增加 sys_server 提供的一种服务类型(GET_TICKS)
3,TestB 和 TestC 之间互相传递消息
- ·main.c 节选
- PUBLIC int get_ticks()
- {
- MESSAGE msg;
- reset_msg(&msg);
- msg.type = GET_TICKS;
- send_recv(BOTH, TASK_SERVER, &msg);
- return msg.RETVAL;
- }
-
- void TestA()
- {
- while (TRUE)
- {
- printf("%d ", get_ticks());
- milli_delay(300);
- }
- }
-
- void TestB()
- {
- MESSAGE _m;
- _m.RETVAL = 1;
- while (TRUE)
- {
- send_recv(SEND, 4, &_m);
- send_recv(RECEIVE, 4, &_m);
- printf("TestB number is [%d]\n", ++_m.RETVAL);
- milli_delay(2000);
- }
- }
-
- void TestC()
- {
- MESSAGE _m;
- while (TRUE)
- {
- send_recv(RECEIVE, 3, &_m);
- printf("TestC number is [%d]\n", ++_m.RETVAL);
- send_recv(SEND, 3, &_m);
- }
- }
- ·sys_task.c
- // ----------------------------
- // <systask.c>
- // Jack Zheng
- // Comment:December 7, 2019
- // ----------------------------
- #include "type.h"
- #include "const.h"
- #include "protect.h"
- #include "string.h"
- #include "proc.h"
- #include "tty.h"
- #include "console.h"
- #include "global.h"
- #include "keyboard.h"
- #include "proto.h"
-
- void task_server()
- {
-
- MESSAGE _m;
- while (TRUE)
- {
- send_recv(RECEIVE, ANY, &_m);
- int src = _m.source;
- switch (_m.type)
- {
- case GET_TICKS: /* 某个进程请求的这个服务 */
- _m.RETVAL = ticks;
- send_recv(SEND, src, &_m);
- break;
-
- default:
- panic("unknown Message type");
- break;
- }
- }
- }
运行:
sys_server 的 GET_TICKS 是在接收到消息之后才解析消息类型然后进行相应的处理!所以进程请求系统任务服务的大致手段是:唤醒系统任务,系统任务解析服务类型,服务!
OK,可以看到,我们的内核从宏内核改为微内核之后优雅了许多,所谓一切都建立在消息上!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。