kernel/ipc.c

来源:互联网 发布:笔记本电池校正软件 编辑:程序博客网 时间:2024/06/17 06:55
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. }   

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 炸臭豆腐剩的油怎么办 油炸久了油发黑怎么办 炸鱼的时候粘锅怎么办 吃了葱蒜有味怎么办 哺乳期喝了抹茶怎么办 干炸小黄鱼凉了怎么办 烧鱼酱油放多了怎么办 夏天腿干燥起皮怎么办 螃蟹柿子同时吃了怎么办 柿子和螃蟹一起吃怎么办 螃蟹和柿子吃了怎么办 今天为什么很多网站打不开怎么办 网上报名人太多服务器卡怎么办 网站换了电脑打不开怎么办 感冒时后背发凉怎么办? 脚扭了脚背疼怎么办 五妙水仙膏干了怎么办 红苹果接不到任务了怎么办 我判刑了家里老母亲怎么办 离婚之前对方把财产转移怎么办 有人侵犯我的名誉权怎么办 耳朵被咬红肿了怎么办 孕29周呼吸困难怎么办 痔疮出血一个星期了怎么办 怀孕长了副乳该怎么办 备孕期间长痔疮怎么办 15年凌度智能钥匙全丢怎么办 西水开发商跑了怎么办 如果房子烂尾了怎么办 小斗鱼出生后喂年丰虾在缸底怎么办 脸上痘痘红肿痒怎么办 签证一定要写酒店地址怎么办 重庆的狗狗死了怎么办 村霸霸占土地该怎么办 母狗生不出来了怎么办 电视锁屏失败了怎么办? 海尔户户通位置信息改变怎么办 户户通e02智能卡通信失败怎么办 户户通e04未授权怎么办 查环保没生意做怎么办 怎么办扬大牛奶直销点