zoukankan      html  css  js  c++  java
  • IPC的使用

    IPC,Inter-Processor Communication是SYS/BIOS处理核间通信的组件:

    IPC的几种应用方式:

    1.最小使用(Minimal use)

    这种情况是通过核间的通知机制(notification)来实施的,而一个通知所携带的信息是非常小的(一般是32bits),所以称为最小使用。这种方式一般是用于处理核间的简单同步,却无法处理复杂的消息传递。

    这种情况下,需要利用到Notify模块的APIs函数,比如通过Notify_sendEvent()函数给某个特定核传递一个事件,我们可以给特定事件动态注册反馈函数。由于一个通知(notification)所携带的信息是极少的,所以只能给处理器发送一个事件号,而这个事件号所代表的反馈函数决定之后的动作。另外一些数据以函数参数方式,也可以被送出。

    2.增加数据通路(Add data passing)

    这种情况是在前面的最小使用机制下,在核间增加了一个传递链表元素的数据通路,这个链表的实施一般是使用共享内容并通过门(gates)来管理同步。 

    这种情况是在最小使用上,增加了一个ListMP模块用于共享链表元素。 
    ListMP模块是一个双向链表,另外ListMP需要用到共离内存,所以SharedRegion模块也需要被使用,另外ListMP通过NameServer模块中来管理名称/值,同时使用GateMP模块来防止链表元素被多个处理器同时读取。

    3.增加动态分配(Add dynamic allocation)

    这种情况下,增加了从堆中动态分配链表元素的功能。

    这种情况在上种情况下,增加了一个Heap*MP模块,这个模块主要用于从堆中给链表动态分配内存。

     

    4.强大但易用的消息机制(Powerful but easy-to-use messaging)

    这种情况下利用MessageQ模块来传递消息。 

    除了Notify通知机制,还可以利用MessageQ来实现更为复杂的核间通信,在这种情况下,只需要配置MultiProc和SharedRegion模块就可以了,而Ipc_start()函数将自动为我们实现上面灰色模块的配置。

    最小使用(Minimal use)情况举例

    打开CCS自带例程

    点击编译后,查看有无出错;导入目标配置文件.ccxml,这里选择的仍然是C6678 Device Functional Simulator, Little Endian:

    选中Group,点击运行:

      结果分析

    1.各核打印:

     这段是在main()中出现的结果,每个核都会执行各自的main():

     System_printf("main: MultiProc id = %d
    ", MultiProc_self());
     System_printf("main: MultiProc name = %s
    ", 
     MultiProc_getName(MultiProc_self()));

     2.各核注册事件,并表明其反馈函数:

     status = Notify_registerEvent(srcProc, INTERRUPT_LINE, EVENTID,
                                      (Notify_FnNotifyCbck)cbFxn, NULL);

    核0执行同时释放信号量,在核0释放信号量semHandle之前,其他核都处理等待信号量释放中

     

    核0通过给核1发送事件,触发反馈函数,在反馈函数中semHandle归一,注意这个激活的信号量是在核1中的

     status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, seq, 
                        TRUE);

     激活核1的信号量后,核0打印结果,并等待其信号量的结果,所有核的信号量都初始为0:

     System_printf("tsk1_func: Sent request #%d to %s
    ", seq,
                    MultiProc_getName(dstProc));
     /* wait forever on a semaphore, semaphore is posted in callback */
                Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);

    以下是总共八个核,分别执行了NUMLOOPS次(这里设置的是10次)

     下一个核信号被激活,开始执行:

      /* wait forever on a semaphore, semaphore is posted in callback */
     Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
    
     System_printf("tsk1_func: Received request #%d from %s
    ", seq,
     MultiProc_getName(recvProcId));

    同时通过反馈函数将当前核的下一个核激活:

     status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, seq, 
                        TRUE);

    完成发送事件:

     System_printf("tsk1_func: Sent request #%d to %s
    ", seq,
                    MultiProc_getName(dstProc));

    退出任务循环,同时退出当前核的BIOS:

    多核IPC的配置

    1.IPC的启动非常简单,在导入Ipc头文件后,在main()函数中调用Ipc_start()就能根据.cfg文件中配置启动IPC所需要的模块,比如默认情况下Ipc_start()会调用Notify_start()之类,不过要启动这些模块,需要保证提前在.cfg中添加了这些模块。
    2.IPC的配置是在.cfg中完成的,配置IPC首先需要申明,当前Notify等相关模块也需要提前申明,这里如果不清楚IPC所需要的相关模块,最好使用自带IPC例程作为模块。
     var Ipc = xdc.useModule('ti.sdo.ipc.Ipc');

    3.设置同步的核数

           Ipc.procSync = Ipc.ProcSync_ALL;
           这里Ipc.ProcSync_ALL 表示Ipc_start会自动将所有的核都启动了
           Ipc.ProcSync_PAIR 表示只启动部分核,需要启动的核要通过Ipc_attach()来启动,这个默认选项
           Ipc.ProcSync_NONE 表示Ipc_start()不会同步任何核

    4.核间的连接方法Ipc_attach()及Ipc_detach()

           这两个函数的使用,需要.cfg文件中配置了Ipc.ProcSync_PAIR 
           Ipc_attach的使用方法非常简单,在Ipc_start()之后直接输入:
      Ipc_attach(#coreID),#coreID表示需要连接的核ID号,如Ipc_attach(0)表示连接核0。

       不过需要注意的是:

           a) 核的连接一定要按照ID号从小到大的顺序进行,比如当前核必须先连接了核0,才能连接核1,之后才能连接核2
           b) 另外两核之间的相互连接必须先满足ID号小的先连接ID号大的,比如只有当核0连接核1后,核1才能连接到核0
           c) 由于核的连接并不是一次就能成功的,所以一般需要加一个循环等待的过程,一般使用方法如下:
           
     
     while(Ipc_attach(#coreID)<0)
    {
          Task_sleep(1);
    }

           Ipc_detach()的使用方法同Ipc_attach()是类似的,不过它的功能是解除连接。

    主从核之间的通信

    前面介绍IPC核间通信例子,是每个核同所有核之间都有连接,而各核之间连接都是相同且双向,而在很多情况下,我们并不需要如此多的核,或者许多核间连接也是不必要的,这些情况下使用Ipc.ProcSync_ALL未免太不高效。 
    下面我们介绍的例子是核间的主从通信,选择三个核,选择一个主核,另外两个是副核,主核core0同副核之间有相互连接,而副核core1与副核core2之间没有连接,这个主从通信主要完成以下事件:
    主核向两从核发送事件,激活从核,使其执行任务。
    两核完成任务后,向主核发送事件,主核继续执行其任务。
    1.在.cfg文件中设置procSync
          改为Ipc.procSync = Ipc.ProcSync_PAIR;

    2.修改源文件为:

    #include <xdc/std.h>
    
    /*  -----------------------------------XDC.RUNTIME module Headers    */
    #include <xdc/runtime/System.h>
    
    /*  ----------------------------------- IPC module Headers           */
    #include <ti/ipc/MultiProc.h>
    #include <ti/ipc/Notify.h>
    #include <ti/ipc/Ipc.h>
    /*  ----------------------------------- BIOS6 module Headers         */
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/BIOS.h>
    
    /*  ----------------------------------- To get globals from .cfg Header */
    #include <xdc/cfg/global.h>
    
    #define INTERRUPT_LINE  0
    
    /* Notify event number that the app uses */
    #define EVENTID         10
    
    /* Number of times to run the loop */
    #define NUMLOOPS        3
    
    UInt32 times = 0;
    UInt16 recvnumes = 0;
    
    #define masterProc 0
    #define sloverProc1 1
    #define sloverProc2 2
    #define sloverNum 2
    
    /*
     *  ======== cbFxn ========
     *  This function was registered with Notify. It is called when any event is
     *  sent to this processor.
     */
    Void cbFxn(UInt16 procId, UInt16 lineId,
               UInt32 eventId, UArg arg, UInt32 payload)
    {
        /* The payload is a sequence number. */
    
        if(procId!=masterProc) // 主核注册函数
        {
            recvnumes++;  // 接收从核的数目
            if(recvnumes==sloverNum) // 当收到全部从核回复的信息
            {
                recvnumes=0;
                Semaphore_post(semHandle);
            }
        }
        else
        {
            times = payload; // 执行次数
            Semaphore_post(semHandle);
        }
    }
    
    
    /*
     *  ======== tsk0_func ========
     *  Sends an event to the next processor then pends on a semaphore.
     *  The semaphore is posted by the callback function.
     */
    Void tsk0_func(UArg arg0, UArg arg1)
    {
        Int i = 1;
        Int status;
        
        if (MultiProc_self() == masterProc)
        {
            while (i <= NUMLOOPS)
            {
    
                /* 这里可以添加主核需要执行的任务代码*/
    
                /* Send an event to the next processor */
                status = Notify_sendEvent(sloverProc1, INTERRUPT_LINE, EVENTID, i,
                        TRUE);
                status = Notify_sendEvent(sloverProc2, INTERRUPT_LINE, EVENTID, i,
                        TRUE);
    
                /* Continue until remote side is up */
                if (status < 0)
                {
                    continue;
                }
    
                System_printf("MasterCore Sent Event to SloverCores in %d
    ", i);
    
                /* Wait to be released by the cbFxn posting the semaphore */
                Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); // 主核等待所有从核完成其工作返回
    
                System_printf("MasterCore Received Event from All SloverCores in %d
    ",i);
    
                /* increment for next iteration */
                i++;
            }
        }
        else {
            while (times < NUMLOOPS)
            {
    
                /* wait forever on a semaphore, semaphore is posted in callback */
                Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); // 等待主核通知开始执行任务
    
                System_printf("SloverCore%d Received Event from MasterCore in %d
    ", MultiProc_self(),times);
    
                /* 这里可以添加从核执行的任务*/
    
                /* Send an event to the next processor */
                status = Notify_sendEvent(masterProc, INTERRUPT_LINE, EVENTID, times,
                        TRUE);
                if (status < 0) {
                    System_abort("sendEvent to MasterCore failed
    ");
                }
    
                System_printf("SloverCore%d sent Event from MasterCore in %d
    ", MultiProc_self(),times);
            }
        }
    
        System_printf("Test completed
    ");
        BIOS_exit(0);
    }
    
    /*
     *  ======== main ========
     *  Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers 
     *  for an incoming event
     */
    Int main(Int argc, Char* argv[])
    {
        Int status;
    
        status = Ipc_start();
        if (status < 0)
        {
            System_abort("Ipc_start failed
    ");
        }
        
        /*
        这里主要根据主核和从核的角色分别添加连接任务:主核同两个从核都有连接,而从核只与主核有链接
        在添加核间连接后,分别给核间连接注册事件
         */
        if(MultiProc_self()==masterProc)
        {
            while(Ipc_attach(sloverProc1)){
                Task_sleep(1);
            }// 完成从核1的连接
            while(Ipc_attach(sloverProc2)){
                Task_sleep(1);
            }// 完成从核2的连接
    
            status = Notify_registerEvent(sloverProc1, INTERRUPT_LINE, EVENTID,
                                          (Notify_FnNotifyCbck)cbFxn, NULL);
            if (status < 0) {
                System_abort("Notify_registerEvent for sloverCore1 failed
    ");
            }// 完成从核1的事件注册
    
            status = Notify_registerEvent(sloverProc2, INTERRUPT_LINE, EVENTID,
                                          (Notify_FnNotifyCbck)cbFxn, NULL);
            if (status < 0) {
                System_abort("Notify_registerEvent for sloverCore2 failed 
    ");
            }// 完成从核2的事件注册
    
        }
        else{
    
            while(Ipc_attach(masterProc))
            {
                Task_sleep(1);
            }// 完成主核0的连接
    
            status = Notify_registerEvent(masterProc, INTERRUPT_LINE, EVENTID,
                                          (Notify_FnNotifyCbck)cbFxn, NULL);
            if (status < 0) {
                System_abort("Notify_registerEvent for masterCore0 failed
    ");
            }// 完成主核0的事件注册
    
        }
    
        BIOS_start();
        
        return (0);
    }

    仿真调试的结果:

    从结果上看,当从核分别收到了来自主核的事件时,同时开始任务,当从核任务全部完成后,主核才开始其任务。  

  • 相关阅读:
    iOS APP上线流程
    iOS开发:cocoapods的使用
    Swift:函数和闭包
    OC中单例的各种写法及基本讲解
    iOS:死锁
    iOS传值方式:属性,代理,block,单例,通知
    iOS支付
    Binary Tree Preorder Traversal——经典算法的迭代求解(前序,中序,后序都在这里了)
    Largest Number——STL的深层理解
    const、volatile、mutable的用法
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/8656382.html
Copyright © 2011-2022 走看看