zoukankan      html  css  js  c++  java
  • IPC

    IPC是Inter-Process Communication的缩写,直译为进程间通信,说白了就是进程间发消息。我们在上一节中把这种消息传递比作邮政系统,但实际上这种比喻并不全对。有的消息机制是很像收发邮件的,这种叫做异步IPC,意思是说,发信者发完就去干别的了,收信者也一样,看看信箱里没信,也不坐在旁边傻等。而有另一种消息机制正好相反,被称为同步IPC,它不像邮寄,倒像接力赛,发送者一直等到接收者收到消息才肯放手,接收者也一样,接不到就一直等着,不干别的。
    当然你可以把同步IPC也比作邮寄,只不过寄信的人从把信投到信箱里的那一刻开始,就住在邮局不走了,其他什么也不干了,就等着邮局说:“哥们儿,你的信对方已经收到了,放心回家吧!”这才恋恋不舍地离开。收信的也一样,一旦决定收信,就守在自家信箱前面不走了,一直等,连觉也不睡,望穿秋水,等信拿在手里了,这才回屋,每收一次信,就得瘦个十几斤。
    我们都是性情中人,我们选择傻等,或曰同步IPC。
    同步IPC有若干的好处,比如:
    • 操作系统不需要另外维护缓冲区来存放正在传递的消息;
    • 操作系统不需要保留一份消息副本;
    • 操作系统不需要维护接收队列(发送队列还是需要的);
    • 发送者和接收者都可在任何时刻清晰且容易地知道消息是否送达;
    • 从实现系统调用的角度来看,同步IPC更加合理──当使用系统调用时,我们的确需要等待内核返回结果之后再继续。
    这些特性读者可能无法一下子全部明白,不要紧,我们接下来写完代码,你就全都明白了。
    实现IPC
    Minix的IPC机制我们已经明白了,它的核心乃在于“int SYSVEC”这个软中断以及与之对应的sys_call()这个函数。增加一个系统调用对我们来讲已是信手拈来的事,按照表7.6一步一步来就好了。我们把这个新的系统调用起名为sendrec。sendrec和sys_sendrec的函数体分别见下面两段代码:
    25 sendrec:
    26         mov eax, _NR_sendrec
    27         mov ebx, [esp + 4] ; function
    28         mov ecx, [esp + 8] ; src_dest
    29         mov edx, [esp + 12] ; p_msg
    30         int INT_VECTOR_SYS_CALL
    31         ret
    53 /*****************************************************************************
    54 * sys_sendrec
    55 *****************************************************************************/
    56 /**
    57 * <Ring 0> The core routine of system call ‘sendrec()’.
    58 *
    59 * @param function SEND or RECEIVE
    60 * @param src_dest To/From whom the message is transferred.
    61 * @param m Ptr to the MESSAGE body.
    62 * @param p The caller proc.
    63 *
    64 * @return Zero if success.
    65 *****************************************************************************/
    66 PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, struct proc* p)
    67 {
    68         assert(k_reenter == 0); /* make sure we are not in ring0 */
    69         assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) ||
    70         src_dest == ANY ||
    71         src_dest == INTERRUPT);
    72
    73         int ret = 0;
    74         int caller = proc2pid(p);
    75         MESSAGE* mla = (MESSAGE*)va2la(caller, m);
    76         mla->source = caller;
    77
    78         assert(mla->source != src_dest);
    79
    80         /**
    81         * Actually we have the third message type: BOTH. However, it is not
    82         * allowed to be passed to the kernel directly. Kernel doesn’t know
    83         * it at all. It is transformed into a SEND followed by a RECEIVE
    84         * by ‘send_recv()’.
    85         */
    86         if (function == SEND) {
    87                 ret = msg_send(p, src_dest, m);
    88                 if (ret != 0)
    89                 return ret;
    90         }
    91         else if (function == RECEIVE) {
    92                 ret = msg_receive(p, src_dest, m);
    93                 if (ret != 0)
    94                 return ret;
    95         }
    96         else {
    97                 panic(”{sys_sendrec}␣invalid␣function:␣”
    98                 ”%d␣(SEND:%d,␣RECEIVE:%d).”, function, SEND, RECEIVE);
    99         }
    100       
    101         return 0;
    102 }
    表7.6的最后一步中提到,如果参数个数与以前的系统调用比有所增加,则需要修改kernel.asm中的sys_call。额外要注意,我们新加的参数是通过edx这个参数传递的,而save这个函数中也用到了寄存器dx,所以我们同时需要修改save,见如下代码:
       311 ; =============================================================================
       312 ; save
       313 ; =============================================================================
       314 save:
       315         pushad ; ‘.
       316         push ds ; |
       317         push es ; | 保存原寄存器值
       318         push fs ; |
       319         push gs ; /
       320
       321         ;; 注意,从这里开始,一直到‘mov esp, StackTop’,中间坚决不能用push/pop 指令,
       322         ;; 因为当前esp 指向proc_table 里的某个位置,push 会破坏掉进程表,导致灾难性后果!
       323
    => 324         mov esi, edx ; 保存edx,因为edx 里保存了系统调用的参数
       325         ;(没用栈,而是用了另一个寄存器esi)
       326         mov dx, ss
       327         mov ds, dx
       328         mov es, dx
       329         mov fs, dx
       330
    => 331         mov edx, esi ; 恢复edx
       332
       333         mov esi, esp                         ;esi = 进程表起始地址
       334
       335         inc dword [k_reenter]                ;k_reenter++;
       336         cmp dword [k_reenter], 0             ;if(k_reenter ==0)
       337         jne .1                               ;{
       338         mov esp, StackTop                    ; mov esp, StackTop <--切换到内核栈
       339         push restart                         ; push restart
       340         jmp [esi + RETADR - P_STACKBASE]     ; return;
       341 .1:                                          ;} else { 已经在内核栈,不需要再切换
       342         push restart_reenter                 ; push restart_reenter
       343         jmp [esi + RETADR - P_STACKBASE]     ; return;
       344                                              ;}
       345
       346
       347 ; =============================================================================
       348 ; sys_call
       349 ; =============================================================================
       350 sys_call:
       351         call save
       352
       353         sti
       354         push esi
       355
       356         push dword [p_proc_ready]
    => 357         push edx
       358         push ecx
       359         push ebx
       360         call [sys_call_table + eax * 4]
    => 361         add esp, 4 * 4
       362
       363         pop esi
       364         mov [esi + EAXREG - P_STACKBASE], eax
       365         cli
       366
       367         ret
    sys_sendrec()这个函数被设计得相当简单,它可以描述为:把SEND消息交给msg_send()处理,把RECEIVE消息交给msg_receive()处理。
    msg_send()和msg_receive()这两个函数我们过一会儿细细分解,先来看看之前没出现过的assert()和panic()。这两个函数虽然起的是辅助作用,但绝对不是可有可无,因为在我们接下来要处理的消息收发中,有一些编程细节还真容易让人迷糊,这时候assert()就大显神威了,它会在错误被放大之前通知你。panic()的作用也类似,用于通知你发生了严重的错误。
  • 相关阅读:
    用fiddler测试ip轮询
    ubuntu下安装fiddler
    Andriod相机开发关于startPreview Failed的错误的特别记录(重要)
    我的Cocos2dx开发模式
    Android WebView导入HTML使Js生效的方法
    Lua快捷键
    String,StringBuilder,StringBuffer的对比测试
    重构视角(摘抄)
    String属于“假引用类型”,代码为证(一个String引发的血案...)
    static class
  • 原文地址:https://www.cnblogs.com/broadview/p/1490077.html
Copyright © 2011-2022 走看看