kernel/ipc.c

Code:
  1. /*  
  2.     By Marcus Xing  
  3.     kernel/ipc.c  
  4.     IPC有关的代码  
  5. */  
  6.   
  7. #include "type.h"   
  8. #include "const.h"   
  9. #include "ipc.h"   
  10. #include "console.h"   
  11. #include "tty.h"   
  12. #include "protect.h"   
  13. #include "proc.h"   
  14. #include "global.h"   
  15. #include "proto.h"   
  16.   
  17. /*-------------------------------------------------------------Proc_Send_Receive    
  18.     系统进程,负责接受消息,转发消息  
  19. */  
  20. void Proc_Send_Receive()   
  21. {   
  22.     Message m;   
  23.     /* 死循环不断的接收消息转发消息 */  
  24.     while(1)   
  25.     {   
  26.         Send_Receive_Shell(RECEIVE,ANY,&m);   
  27.         int sender = m.src_proc_pid;    /* 得知是谁发的 */  
  28.            
  29.         switch(m.msg_type)   
  30.         {   
  31.             /* 返回ticks消息 */  
  32.             case GET_TICKS:   
  33.                 m.r1 = d_Ticks;     /* 将ticks值给消息的第一个返回值 */  
  34.                 Send_Receive_Shell(SEND,sender,&m);     /* 原路发回 */  
  35.                 break;   
  36.                
  37.             default:   
  38.                 Panic("Unknown Message Type!");   
  39.                 break;   
  40.         }   
  41.     }   
  42. }   
  43.   
  44. /*-------------------------------------------------------------Send_Receive_Shell    
  45.     RING 1-3下调用的壳  
  46.     发送或接收消息使用  
  47. */  
  48. void Send_Receive_Shell(int function,int send_recev_pid,Message *m)   
  49. {   
  50.     switch(function)   
  51.     {   
  52.         /* 直接交给系统调用处理 */  
  53.         case SEND:   
  54.         case RECEIVE:   
  55.             Send_Receive(function,send_recev_pid,m);   
  56.             break;   
  57.                
  58.         /* BOTH的话,先发再收 */  
  59.         case BOTH:   
  60.             Send_Receive(SEND,send_recev_pid,m);   
  61.             Send_Receive(RECEIVE,send_recev_pid,m);   
  62.             break;   
  63.                
  64.         default:   
  65.             break;   
  66.     }   
  67. }   
  68.   
  69. /*------------------------------------------------------------------Is_Dead_Lock  
  70.     RING 0下调用  
  71.     src_pid进程要向dest_pid进程发消息  
  72.     判断dest_pid进程是否直接或间接向src_pid进程发消息  
  73.     注意在RING 0下调用Assert的话reenter值为1,调度程序将不调度其它进程  
  74.     从而死循环  
  75. */  
  76. void Is_Dead_Lock(int src_pid,int dest_pid)   
  77. {   
  78.     Assert(src_pid >= 0 || src_pid < d_Cur_Proc_Num);   
  79.     Assert(dest_pid >= 0 || dest_pid < d_Cur_Proc_Num);   
  80.     Assert(src_pid != dest_pid);   
  81.        
  82.     PCB *p_src = PCB_Table + src_pid;   
  83.     PCB *p_dest = PCB_Table + dest_pid;   
  84.        
  85.     while(1)   
  86.     {   
  87.         /* 如果接收进程没有向发送进程发消息,则表示通过检测 */  
  88.         if(p_dest->send_to == NO_PROC)   
  89.         {   
  90.             break;   
  91.         }   
  92.         Assert(p_dest->ipc_status & SENDING);   
  93.         Assert(p_dest->send_to != src_pid);   
  94.         p_dest = PCB_Table + p_dest->send_to;       /* 接收进程链到下一个进程 */  
  95.     }   
  96. }   
  97.   
  98. /*----------------------------------------------------------------------MSG_Send  
  99.     RING 0调用  
  100.     发送消息   
  101. */  
  102. void MSG_Send(int receive_pid,Message *m,PCB *caller)   
  103. {   
  104.   /* 检测是否死锁 */  
  105.   Is_Dead_Lock(caller - PCB_Table,receive_pid);   
  106.        
  107.     PCB *p_receive = PCB_Table + receive_pid;   
  108.        
  109.     /* 如果有进程在接收此进程发消息 */  
  110.     if((p_receive->ipc_status & RECEIVING) &&    
  111.         (p_receive->receive_from == caller - PCB_Table) ||   
  112.         (p_receive->receive_from == ANY))   
  113.     {   
  114.         /* 把消息拷贝到接收进程的message中 */  
  115.         Memory_Copy(p_receive->p_message,m,sizeof(Message));   
  116.         /* 清理工作 */  
  117.         p_receive->p_message = 0;   
  118.         p_receive->receive_from = NO_PROC;   
  119.         p_receive->ipc_status &= ~RECEIVING;   
  120.         p_receive->ipc_status |= NO_BLOCK;  /* 解除接收进程的阻塞,重新可以被调度 */  
  121.     }   
  122.     /* 如果没有进程在接收此消息 */  
  123.     else  
  124.     {   
  125.            
  126.         caller->ipc_status = 0;             /* 发送进程状态为阻塞 */  
  127.         caller->ipc_status |= SENDING;      /* 发送进程状态为正在发送 */  
  128.         caller->send_to = receive_pid;      /* 发送进程PCB的sendto设相应值 */  
  129.         caller->p_message = m;              /* 发送进程的消息指针设相应值 */  
  130.            
  131.         /*   
  132.             把发送进程PCB添加到接收进程的发送队列的末尾   
  133.             分2种情况  
  134.         */  
  135.   
  136.         /* 如果发送队列此时不为空,则链到队首尾 */  
  137.         if(p_receive->sending_queue_first != 0)   
  138.         {   
  139.             PCB *p_pcb = p_receive->sending_queue_first;   
  140.             while(p_pcb->sending_queue_next != 0)   
  141.             {   
  142.                 p_pcb = p_pcb->sending_queue_next;   
  143.             }   
  144.             p_pcb->sending_queue_next = caller;   
  145.         }   
  146.         /* 如果发送队列为空,则直接链到队首 */  
  147.         else  
  148.         {   
  149.             p_receive->sending_queue_first = caller;   
  150.         }   
  151.         caller->sending_queue_next = 0;   
  152.         Schedule();     /* 重新调度 */  
  153.     }   
  154. }   
  155.        
  156. /*-------------------------------------------------------------------MSG_Receive  
  157.     RING 0调用  
  158.     接收消息  
  159. */  
  160. void MSG_Receive(int send_pid,Message *m,PCB *caller)   
  161. {   
  162.     PCB *p_send = 0;   
  163.     PCB *p_prev = 0;   
  164.     int is_ready = 0;   
  165.        
  166.     /* 接收进程的发送队列不为空,说明已有发送进程发消息给他 */  
  167.     if(caller->sending_queue_first != 0)   
  168.     {   
  169.         /* 如果可接收任何进程的消息 */  
  170.         if(send_pid == ANY)   
  171.         {   
  172.             /* 准备复制发送队列的第一个进程的消息 */  
  173.             p_send = caller->sending_queue_first;   
  174.             is_ready = 1;   
  175.         }   
  176.         /* 接收指定发送进程的消息 */  
  177.         else  
  178.         {   
  179.             /* 遍历发送队列,寻找指定的发送进程 */  
  180.             p_send = caller->sending_queue_first;   
  181.             while((p_send != 0) && ((p_send - PCB_Table) != send_pid))   
  182.             {      
  183.                 p_prev = p_send;   
  184.                 p_send = p_send->sending_queue_next;   
  185.             }   
  186.             /* 如果p_send不为0,则找到,否则反之 */  
  187.             if(p_send != 0)   
  188.             {   
  189.                 is_ready = 1;   
  190.             }   
  191.             else  
  192.             {   
  193.                 is_ready = 0;   
  194.             }   
  195.         }              
  196.     }   
  197.        
  198.     /* 如果可以接收消息 */  
  199.     if(is_ready == 1)   
  200.     {   
  201.         /*   
  202.             如果p_prev为0则说明指定接收的进程在发送队列的首位   
  203.             否则在发送队列中间  
  204.             然后根据不同的2种策略把发送进程从发送队列中拿掉  
  205.         */  
  206.         if(p_prev == 0)   
  207.         {   
  208.             caller->sending_queue_first = p_send->sending_queue_next;   
  209.         }   
  210.         else  
  211.         {   
  212.             p_prev->sending_queue_next = p_send->sending_queue_next;   
  213.         }   
  214.         /* 复制消息 */  
  215.         Memory_Copy(m,p_send->p_message,sizeof(Message));   
  216.         /* 收尾工作 */  
  217.         p_send->sending_queue_next = 0;   
  218.         p_send->ipc_status |= NO_BLOCK;   
  219.         p_send->ipc_status &= ~SENDING;   
  220.         p_send->p_message = 0;   
  221.         p_send->send_to = NO_PROC;   
  222.     }   
  223.     /* 如果不能接收消息 */  
  224.     else  
  225.     {   
  226.         /* 设置状态等信息 */  
  227.         caller->ipc_status |= RECEIVING;   
  228.         caller->ipc_status &= ~NO_BLOCK;   
  229.         caller->receive_from = send_pid;   
  230.         caller->p_message = m;   
  231.         Schedule();     /* 重新调度 */  
  232.     }   
  233. }   

 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值