kernel/ipc.c
来源:互联网 发布:笔记本电池校正软件 编辑:程序博客网 时间:2024/06/17 06:55
- /*
- By Marcus Xing
- kernel/ipc.c
- IPC有关的代码
- */
- #include "type.h"
- #include "const.h"
- #include "ipc.h"
- #include "console.h"
- #include "tty.h"
- #include "protect.h"
- #include "proc.h"
- #include "global.h"
- #include "proto.h"
- /*-------------------------------------------------------------Proc_Send_Receive
- 系统进程,负责接受消息,转发消息
- */
- void Proc_Send_Receive()
- {
- Message m;
- /* 死循环不断的接收消息转发消息 */
- while(1)
- {
- Send_Receive_Shell(RECEIVE,ANY,&m);
- int sender = m.src_proc_pid; /* 得知是谁发的 */
- switch(m.msg_type)
- {
- /* 返回ticks消息 */
- case GET_TICKS:
- m.r1 = d_Ticks; /* 将ticks值给消息的第一个返回值 */
- Send_Receive_Shell(SEND,sender,&m); /* 原路发回 */
- break;
- default:
- Panic("Unknown Message Type!");
- break;
- }
- }
- }
- /*-------------------------------------------------------------Send_Receive_Shell
- RING 1-3下调用的壳
- 发送或接收消息使用
- */
- void Send_Receive_Shell(int function,int send_recev_pid,Message *m)
- {
- switch(function)
- {
- /* 直接交给系统调用处理 */
- case SEND:
- case RECEIVE:
- Send_Receive(function,send_recev_pid,m);
- break;
- /* BOTH的话,先发再收 */
- case BOTH:
- Send_Receive(SEND,send_recev_pid,m);
- Send_Receive(RECEIVE,send_recev_pid,m);
- break;
- default:
- break;
- }
- }
- /*------------------------------------------------------------------Is_Dead_Lock
- RING 0下调用
- src_pid进程要向dest_pid进程发消息
- 判断dest_pid进程是否直接或间接向src_pid进程发消息
- 注意在RING 0下调用Assert的话reenter值为1,调度程序将不调度其它进程
- 从而死循环
- */
- void Is_Dead_Lock(int src_pid,int dest_pid)
- {
- Assert(src_pid >= 0 || src_pid < d_Cur_Proc_Num);
- Assert(dest_pid >= 0 || dest_pid < d_Cur_Proc_Num);
- Assert(src_pid != dest_pid);
- PCB *p_src = PCB_Table + src_pid;
- PCB *p_dest = PCB_Table + dest_pid;
- while(1)
- {
- /* 如果接收进程没有向发送进程发消息,则表示通过检测 */
- if(p_dest->send_to == NO_PROC)
- {
- break;
- }
- Assert(p_dest->ipc_status & SENDING);
- Assert(p_dest->send_to != src_pid);
- p_dest = PCB_Table + p_dest->send_to; /* 接收进程链到下一个进程 */
- }
- }
- /*----------------------------------------------------------------------MSG_Send
- RING 0调用
- 发送消息
- */
- void MSG_Send(int receive_pid,Message *m,PCB *caller)
- {
- /* 检测是否死锁 */
- Is_Dead_Lock(caller - PCB_Table,receive_pid);
- PCB *p_receive = PCB_Table + receive_pid;
- /* 如果有进程在接收此进程发消息 */
- if((p_receive->ipc_status & RECEIVING) &&
- (p_receive->receive_from == caller - PCB_Table) ||
- (p_receive->receive_from == ANY))
- {
- /* 把消息拷贝到接收进程的message中 */
- Memory_Copy(p_receive->p_message,m,sizeof(Message));
- /* 清理工作 */
- p_receive->p_message = 0;
- p_receive->receive_from = NO_PROC;
- p_receive->ipc_status &= ~RECEIVING;
- p_receive->ipc_status |= NO_BLOCK; /* 解除接收进程的阻塞,重新可以被调度 */
- }
- /* 如果没有进程在接收此消息 */
- else
- {
- caller->ipc_status = 0; /* 发送进程状态为阻塞 */
- caller->ipc_status |= SENDING; /* 发送进程状态为正在发送 */
- caller->send_to = receive_pid; /* 发送进程PCB的sendto设相应值 */
- caller->p_message = m; /* 发送进程的消息指针设相应值 */
- /*
- 把发送进程PCB添加到接收进程的发送队列的末尾
- 分2种情况
- */
- /* 如果发送队列此时不为空,则链到队首尾 */
- if(p_receive->sending_queue_first != 0)
- {
- PCB *p_pcb = p_receive->sending_queue_first;
- while(p_pcb->sending_queue_next != 0)
- {
- p_pcb = p_pcb->sending_queue_next;
- }
- p_pcb->sending_queue_next = caller;
- }
- /* 如果发送队列为空,则直接链到队首 */
- else
- {
- p_receive->sending_queue_first = caller;
- }
- caller->sending_queue_next = 0;
- Schedule(); /* 重新调度 */
- }
- }
- /*-------------------------------------------------------------------MSG_Receive
- RING 0调用
- 接收消息
- */
- void MSG_Receive(int send_pid,Message *m,PCB *caller)
- {
- PCB *p_send = 0;
- PCB *p_prev = 0;
- int is_ready = 0;
- /* 接收进程的发送队列不为空,说明已有发送进程发消息给他 */
- if(caller->sending_queue_first != 0)
- {
- /* 如果可接收任何进程的消息 */
- if(send_pid == ANY)
- {
- /* 准备复制发送队列的第一个进程的消息 */
- p_send = caller->sending_queue_first;
- is_ready = 1;
- }
- /* 接收指定发送进程的消息 */
- else
- {
- /* 遍历发送队列,寻找指定的发送进程 */
- p_send = caller->sending_queue_first;
- while((p_send != 0) && ((p_send - PCB_Table) != send_pid))
- {
- p_prev = p_send;
- p_send = p_send->sending_queue_next;
- }
- /* 如果p_send不为0,则找到,否则反之 */
- if(p_send != 0)
- {
- is_ready = 1;
- }
- else
- {
- is_ready = 0;
- }
- }
- }
- /* 如果可以接收消息 */
- if(is_ready == 1)
- {
- /*
- 如果p_prev为0则说明指定接收的进程在发送队列的首位
- 否则在发送队列中间
- 然后根据不同的2种策略把发送进程从发送队列中拿掉
- */
- if(p_prev == 0)
- {
- caller->sending_queue_first = p_send->sending_queue_next;
- }
- else
- {
- p_prev->sending_queue_next = p_send->sending_queue_next;
- }
- /* 复制消息 */
- Memory_Copy(m,p_send->p_message,sizeof(Message));
- /* 收尾工作 */
- p_send->sending_queue_next = 0;
- p_send->ipc_status |= NO_BLOCK;
- p_send->ipc_status &= ~SENDING;
- p_send->p_message = 0;
- p_send->send_to = NO_PROC;
- }
- /* 如果不能接收消息 */
- else
- {
- /* 设置状态等信息 */
- caller->ipc_status |= RECEIVING;
- caller->ipc_status &= ~NO_BLOCK;
- caller->receive_from = send_pid;
- caller->p_message = m;
- Schedule(); /* 重新调度 */
- }
- }
- kernel/ipc.c
- 家庭安防IPC设备kernel裁剪
- IPC 资源、kernel.shmmax和Oracle 共享内存的调整
- kernel/clock.c
- kernel/console.c
- kernel/global.c
- kernel/init_8253.c
- kernel/init_8259a.c
- kernel/keyboard.c
- kernel/proc.c
- kernel/protect.c
- kernel/system_call.c
- kernel/tty.c
- kernel/clock.c
- kernel/console.c
- kernel/global.c
- kernel/init_8253.c
- kernel/init_8259a.c
- kernel/clock.c
- kernel/console.c
- kernel/global.c
- kernel/init_8253.c
- kernel/init_8259a.c
- kernel/ipc.c
- kernel/keyboard.c
- kernel/proc.c
- kernel/protect.c
- kernel/system_call.c
- kernel/tty.c
- kernel/system_call.asm
- CSS中cursor样式
- kernel/kernel.asm