1    /* 
     2     * Copyright (c) 2010, Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     * */
    32    /*
    33     *  ======== MessageQ.xdc ========
    34     *
    35     */
    36    
    37    package ti.sdo.ipc;
    38    
    39    import xdc.runtime.IHeap;
    40    import xdc.runtime.Assert;
    41    import xdc.runtime.Error;
    42    import xdc.runtime.Diags;
    43    import xdc.runtime.Log;
    44    import xdc.runtime.IGateProvider;
    45    import xdc.runtime.knl.ISync;
    46    
    47    import ti.sysbios.syncs.SyncSem;
    48    
    49    import ti.sdo.ipc.interfaces.IMessageQTransport;
    50    import ti.sdo.utils.NameServer;
    51    import ti.sdo.utils.List;
    52    
    53    import xdc.rov.ViewInfo;
    54    
    55    /*!
    56     *  ======== MessageQ ======== 
    57     *  Message-passing with queuing
    58     *
    59     *  The MessageQ module supports the structured sending and receiving of 
    60     *  variable length messages. This module can be used for homogeneous
    61     *  (DSP to DSP)  or heterogeneous (Arm to DSP) multi-processor messaging. 
    62     * 
    63     *  MessageQ provides more sophisticated messaging than other modules. It is
    64     *  typically used for complex situations such as multi-processor messaging. 
    65     * 
    66     *  The following are key features of the MessageQ module:
    67     *  @p(blist)
    68     *  -Writers and readers can be relocated to another processor with no
    69     *   runtime code changes.
    70     *  -Timeouts are allowed when receiving messages.
    71     *  -Readers can determine the writer and reply back.
    72     *  -Receiving a message is deterministic when the timeout is zero.
    73     *  -Messages can reside on any message queue.
    74     *  -Supports zero-copy transfers.
    75     *  -Can send and receive from any type of thread.
    76     *  -Notification mechanism is specified by application.
    77     *  -Allows QoS (quality of service) on message buffer pools. For example,
    78     *   using specific buffer pools for specific message queues.
    79     *  @p
    80     *
    81     *  Messages are sent and received by being placed on and removed from a
    82     *  message queue. A reader is a thread that gets (reads) messages from a
    83     *  message queue. A writer is a thread that puts (writes) a message to a
    84     *  message queue. Each message queue has one reader and can have many writers.
    85     *  A thread may read from or write to multiple message queues.
    86     *
    87     *  Conceptually, the reader thread owns a message queue. The reader thread
    88     *  creates a message queue. The writer threads open a created message queue
    89     *  to get access to them.
    90     *
    91     *  Message queues are identified by a system-wide unique name. Internally, 
    92     *  MessageQ uses the {@link ti.sdo.utils.NameServer} module for managing 
    93     *  these names. The names are used for opening a message queue.
    94     * 
    95     *  Messages must be allocated from the MessageQ module. Once a message is
    96     *  allocated, it can be sent to any message queue. Once a message is sent, the
    97     *  writer loses ownership of the message and should not attempt to modify the
    98     *  message. Once the reader receives the message, it owns the message. It
    99     *  may either free the message or re-use the message.
   100     *
   101     *  Messages in a message queue can be of variable length. The only
   102     *  requirement is that the first field in the definition of a message must be a
   103     *  {@link #MsgHeader} structure. For example:
   104     *  @p(code)
   105     *  typedef struct MyMsg {
   106     *      MessageQ_MsgHeader header;
   107     *      ...
   108     *  } MyMsg;
   109     *  @p
   110     *
   111     *  The MessageQ API uses the MessageQ_MsgHeader internally. Your application
   112     *  should not modify or directly access the fields in the MessageQ_MsgHeader.
   113     *
   114     *  All messages sent via the MessageQ module must be allocated from a 
   115     *  {@link xdc.runtime.IHeap} implementation. The heap can also be used for
   116     *  other memory allocation not related to MessageQ.
   117     *
   118     *  An application can use multiple heaps. The purpose of having multiple
   119     *  heaps is to allow an application to regulate its message usage. For
   120     *  example, an application can allocate critical messages from one heap of fast
   121     *  on-chip memory and non-critical messages from another heap of slower
   122     *  external memory.
   123     *
   124     *  The {@link #registerHeap} and {@link #registerHeapMeta} are APIs used to
   125     *  assign a MessageQ heapId to a heap. When allocating a message, the heapId
   126     *  is used, not the heap handle. This heapId is actually placed into the 
   127     *  message (part of the {@link #MsgHeader}). Care must be taken when assigning
   128     *  heapIds. Refer to the {@link #registerHeap} and {@link #registerHeapMeta}
   129     *  descriptions for more details.
   130     *
   131     *  MessageQ also supports the usage of messages that are not allocated via the
   132     *  {@link #alloc} function. Please refer to the {@link #staticMsgInit}
   133     *  function description for more details.
   134     *
   135     *  MessageQ supports reads/writes of different thread models. This is
   136     *  accomplished by having the creator of the message queue specify a 
   137     *  {@link xdc.runtime.knl.ISync#Object} via the {@link #synchronizer}
   138     *  configuration parameter. The {@link xdc.runtime.knl.ISync#signal} 
   139     *  portion of the ISync instance is called whenever the {@link #put}
   140     *  is called. The {@link xdc.runtime.knl.ISync#wait} portion is 
   141     *  called in the {@link #get} if and only if there are no messages.
   142     *
   143     *  Since ISyncs are binary, the reader must drain the message queue of all
   144     *  messages before waiting for another signal. For example, if the reader 
   145     *  was a SYSBIOS Swi, the {@link xdc.runtime.knl.ISync} instance 
   146     *  could be a SyncSwi. If a {@link #put} was called, the Swi_post() would 
   147     *  be called. The Swi would run and it must call {@link #get} until no 
   148     *  messages are returned.
   149     * 
   150     *  In a multiple processor system, MessageQ communicates to other
   151     *  processors via {@link IMessageQTransport} instances.  MessageQ supports
   152     *  a high priority and a normal priority transport between any two
   153     *  processors. The IMessageQTransport instances are created via the
   154     *  {@link #SetupTransportProxy}. The instances are responsible for
   155     *  registering themselves with MessageQ. This is accomplished via the
   156     * {@link #registerTransport} function.
   157     */
   158    
   159    @ModuleStartup 
   160    @InstanceInitError
   161    @InstanceFinalize
   162    
   163    module MessageQ
   164    {
   165        /*!
   166         *  ======== QueuesView ========
   167         *  @_nodoc
   168         */
   169        metaonly struct QueuesView {
   170            String  name;
   171            UInt    queueId;
   172        }
   173        
   174        /*!
   175         *  ======== MessagesView ========
   176         *  @_nodoc
   177         */
   178        metaonly struct MessagesView {
   179            Int          seqNum;
   180            Int          msgSize;
   181            String       priority;
   182            String       srcProc;        
   183            String       replyProc;
   184            String       replyId;
   185            Int          msgId;          
   186            String       heap;
   187            Bool         traceEnabled;
   188            Int          version;
   189        }
   190    
   191        /*!
   192         *  ======== ModuleView ========
   193         *  @_nodoc
   194         */
   195        metaonly struct ModuleView {        
   196            String               heaps[];        
   197            String               gate;
   198            UInt16               nextSeqNum;
   199        }
   200    
   201        
   202        /*!
   203         *  ======== rovViewInfo ========
   204         *  @_nodoc
   205         */
   206        @Facet
   207        metaonly config xdc.rov.ViewInfo.Instance rovViewInfo = 
   208            xdc.rov.ViewInfo.create({
   209                viewMap: [
   210                    ['Queues',
   211                        {
   212                            type: xdc.rov.ViewInfo.INSTANCE,
   213                            viewInitFxn: 'viewInitQueues',
   214                            structName: 'QueuesView'
   215                        }
   216                    ],
   217                    ['Messages', 
   218                        {
   219                            type: xdc.rov.ViewInfo.INSTANCE_DATA,
   220                            viewInitFxn: 'viewInitMessages',
   221                            structName: 'MessagesView'
   222                        }
   223                    ],
   224                    ['Module', 
   225                        {
   226                            type: xdc.rov.ViewInfo.MODULE,
   227                            viewInitFxn: 'viewInitModule',
   228                            structName: 'ModuleView'
   229                        }
   230                    ]
   231                ]
   232            });
   233        
   234        /*!
   235         *  ======== LM_setTrace ========
   236         *  Logged when setting the trace flag on a message
   237         *
   238         *  This is logged when tracing on a message is set via
   239         *  {@link #setMsgTrace}.
   240         */
   241        config Log.Event LM_setTrace = {
   242            mask: Diags.USER1,
   243            msg: "LM_setTrace: Message 0x%x (seqNum = %d, srcProc = %d) traceFlag = %d"
   244        };
   245        
   246        /*!
   247         *  ======== LM_alloc ========
   248         *  Logged when allocating a message
   249         *
   250         *  When the {@link #traceFlag} is true, all message allocations
   251         *  are logged.
   252         */
   253        config Log.Event LM_alloc = {
   254            mask: Diags.USER1,
   255            msg: "LM_alloc: Message 0x%x (seqNum = %d, srcProc = %d) was allocated"
   256        };
   257        
   258        /*!
   259         *  ======== LM_staticMsgInit ========
   260         *  Logged when statically initializing a message
   261         *
   262         *  When the {@link #traceFlag} is true, all messages that
   263         *  are statically initialized via {@link #staticMsgInit} are logged.
   264         */
   265        config Log.Event LM_staticMsgInit = {
   266            mask: Diags.USER1,
   267            msg: "LM_staticMsgInit: Message 0x%x (seqNum = %d, srcProc = %d) was set in MessageQ_staticMsgInit"
   268        };
   269        
   270        /*!
   271         *  ======== LM_free ========
   272         *  Logged when freeing a message
   273         *
   274         *  When the {@link #traceFlag} is true, all freeing of messages
   275         *  are logged. If an individual message's tracing was enabled 
   276         *  via {@link #setMsgTrace}, the MessageQ_free is also logged.
   277         */
   278        config Log.Event LM_free = {
   279            mask: Diags.USER1,
   280            msg: "LM_free: Message 0x%x (seqNum = %d, srcProc = %d) was freed"
   281        };
   282        
   283        /*!
   284         *  ======== LM_putLocal ========
   285         *  Logged when a message is placed onto a local queue
   286         *
   287         *  When the {@link #traceFlag} is true, all putting of messages
   288         *  are logged. If an individual message's tracing was enabled 
   289         *  via {@link #setMsgTrace}, the MessageQ_put is also logged.
   290         */
   291        config Log.Event LM_putLocal = {
   292            mask: Diags.USER1,
   293            msg: "LM_putLocal: Message 0x%x (seqNum = %d, srcProc = %d) was placed onto queue 0x%x"
   294        };
   295        
   296        /*!
   297         *  ======== LM_putRemote ========
   298         *  Logged when a message is given to a transport
   299         *
   300         *  When the {@link #traceFlag} is true, all putting of messages
   301         *  to a transport are logged. If an individual message's tracing
   302         *  was enabled  via {@link #setMsgTrace}, the MessageQ_put is 
   303         *  also logged.
   304         */
   305        config Log.Event LM_putRemote = {
   306            mask: Diags.USER1,
   307            msg: "LM_putRemote: Message 0x%x (seqNum = %d, srcProc = %d) was given to processor %d transport"
   308        };
   309        
   310        /*!
   311         *  ======== LM_rcvByTransport ========
   312         *  Logged when a transport receives an incoming message
   313         *
   314         *  When the {@link #traceFlag} is true, all incoming messages
   315         *  are logged. If an individual message's tracing
   316         *  was enabled  via {@link #setMsgTrace}, the receiving of a message is 
   317         *  also logged.
   318         */
   319        config Log.Event LM_rcvByTransport = {
   320            mask: Diags.USER1,
   321            msg: "LM_rcvByTransport: Message 0x%x (seqNum = %d, srcProc = %d) was received"
   322        };
   323        
   324        /*!
   325         *  ======== LM_get ========
   326         *  Logged when a message is received off the queue
   327         *
   328         *  When the {@link #traceFlag} is true, all getting of messages
   329         *  are logged. If an individual message's tracing
   330         *  was enabled  via {@link #setMsgTrace}, the MessageQ_get is 
   331         *  also logged.
   332         */
   333        config Log.Event LM_get = {
   334            mask: Diags.USER1,
   335            msg: "LM_get: Message 0x%x (seqNum = %d, srcProc = %d) was received by queue 0x%x"
   336        };
   337        
   338        /*! MessageQ ID */
   339        typedef UInt32 QueueId;
   340        
   341        /*!
   342         *  ======== SetupTransportProxy ========
   343         *  MessageQ transport setup proxy
   344         */
   345        proxy SetupTransportProxy inherits ti.sdo.ipc.interfaces.ITransportSetup;
   346        
   347        /*!
   348         *  Message priority values. These must match the values defined in
   349         *  ti/ipc/MessageQ.h but are needed here for ROV.
   350         */
   351        const UInt NORMALPRI   = 0;
   352        const UInt HIGHPRI     = 1;
   353        const UInt RESERVEDPRI = 2;
   354        const UInt URGENTPRI   = 3;
   355        
   356        /*!
   357         *  Assert raised when calling API with wrong handle
   358         *
   359         *  Some APIs can only be called with an opened handle (e.g. 
   360         *  {@link #close}. Some can only be called with a created handle
   361         *  (e.g. {@link #get}).
   362         */
   363        config Assert.Id A_invalidContext  = {
   364            msg: "A_invalidContext: Cannot call with an open/create handle"
   365        };
   366                
   367        /*!
   368         *  Assert raised when attempting to free a static message
   369         */
   370        config Assert.Id A_cannotFreeStaticMsg  = {
   371            msg: "A_cannotFreeStaticMsg: Cannot call MessageQ_free with static msg"
   372        };
   373        
   374        /*!
   375         *  Assert raised when an invalid message is supplied
   376         */
   377        config Assert.Id A_invalidMsg  = {
   378            msg: "A_invalidMsg: Invalid message"
   379        };
   380    
   381        /*!
   382         *  Assert raised when an invalid queueId is supplied
   383         */
   384        config Assert.Id A_invalidQueueId  = {
   385            msg: "A_invalidQueueId: Invalid queueId is used"
   386        };
   387    
   388        /*!
   389         *  Assert raised when using an invalid heapId
   390         */
   391        config Assert.Id A_heapIdInvalid  = {
   392            msg: "A_heapIdInvalid: heapId is invalid"
   393        };
   394        
   395        /*!
   396         *  Assert raised when using an invalid procId
   397         */
   398        config Assert.Id A_procIdInvalid  = {
   399            msg: "A_procIdInvalid: procId is invalid"
   400        };
   401        
   402        /*!
   403         *  Assert raised for an invalid MessageQ object 
   404         */
   405        config Assert.Id A_invalidObj  = {
   406            msg: "A_invalidObj: an invalid obj is used"
   407        };
   408    
   409        /*!
   410         *  Assert raised for an invalid parameter 
   411         */
   412        config Assert.Id A_invalidParam  = {
   413            msg: "A_invalidParam: an invalid parameter was passed in"
   414        };
   415    
   416        /*!
   417         *  Assert raised when attempting to send a message to a core
   418         *  where a transport has not been registered.
   419         */
   420        config Assert.Id A_unregisteredTransport  = {
   421            msg: "A_unregisteredTransport: transport is not registered"
   422        };
   423        
   424        /*!
   425         *  Assert raised when attempting to unblock a remote MessageQ or one that
   426         *  has been configured with a non-blocking synchronizer
   427         */
   428        config Assert.Id A_invalidUnblock  = {
   429            msg: "A_invalidUnblock: Trying to unblock a remote MessageQ or a queue with non-blocking synchronizer"
   430        };
   431        
   432        /*!
   433         *  Error raised if all the message queue objects are taken
   434         */
   435        config Error.Id E_maxReached  = {
   436            msg: "E_maxReached: All objects in use. MessageQ.maxRuntimeEntries is %d"
   437        };
   438        
   439        /*!
   440         *  Error raised when heapId has not been registered
   441         */
   442        config Error.Id E_unregisterHeapId  = {
   443            msg: "E_unregisterHeapId: Heap id %d not registered"
   444        };
   445    
   446        /*!
   447         *  Trace setting
   448         *
   449         *  This flag allows the configuration of the default module trace 
   450         *  settings.     
   451         */
   452        config Bool traceFlag = false;    
   453        
   454        /*!
   455         *  Number of heapIds in the system
   456         *
   457         *  This allows MessageQ to pre-allocate the heaps table.
   458         *  The heaps table is used when registering heaps.
   459         *
   460         *  The default is 1. 
   461         *  
   462         *  There is no default heap, so unless the system is only using
   463         *  {@link #staticMsgInit}, the application must register a heap.
   464         */
   465        config UInt16 numHeaps = 1;    
   466        
   467        /*! 
   468         *  Maximum number of MessageQs that can be dynamically created
   469         */
   470        config UInt maxRuntimeEntries = NameServer.ALLOWGROWTH;
   471        
   472        /*! 
   473         *  Gate used to make the name table thread safe
   474         *
   475         *  This gate is used when accessing the name table during 
   476         *  a {@link #create}, {@link #delete}, and {@link #open}.
   477         *
   478         *  This gate is also used to protect MessageQ when growing
   479         *  internal tables in the {@link #create}.
   480         *
   481         *  The table is in local memory, not shared memory. So a
   482         *  single processor gate will work.
   483         *
   484         *  The default will be {@link xdc.runtime.knl.GateThread}
   485         *  instance.
   486         */
   487        config IGateProvider.Handle nameTableGate = null;
   488        
   489        /*! 
   490         *  Maximum length for Message queue names
   491         */
   492        config UInt maxNameLen = 32;
   493    
   494        /*! 
   495         *  Section name is used to place the names table
   496         */
   497        metaonly config String tableSection = null;
   498        
   499        /*!
   500         *  ======== registerHeapMeta ========
   501         *  Statically register a heap with MessageQ
   502         *
   503         *  Build error if heapId is in use.
   504         *
   505         *  @param(heap)        Heap to register
   506         *  @param(heapId)      heapId associated with the heap
   507         */
   508        metaonly Void registerHeapMeta(IHeap.Handle heap, UInt16 heapId);
   509         
   510         /*!
   511         *  ======== registerTransportMeta ========
   512         *  Statically register a transport with MessageQ
   513         *
   514         *  Build error if remote processor already has a transport
   515         *  registered.
   516         *
   517         *  @param(transport)   transport to register
   518         *  @param(procId)      procId that transport communicaties with
   519         *  @param(priority)    priority of transport
   520         */
   521         metaonly Void registerTransportMeta(IMessageQTransport.Handle transport, UInt16 procId, UInt priority);
   522         
   523        /*! @_nodoc
   524         *  ======== attach ========
   525         *  Calls the {@link #SetupProxy} to setup the MessageQ transports.
   526         */
   527        Int attach(UInt16 remoteProcId, Ptr sharedAddr);
   528        
   529        /*! @_nodoc
   530         *  ======== detach ========
   531         *  Calls the {@link #SetupProxy} to detach the MessageQ transports.
   532         */
   533        Int detach(UInt16 remoteProcId);
   534        
   535        /*! @_nodoc
   536         *  ======== sharedMemReq ========
   537         *  Returns the amount of shared memory used by one transport instance.
   538         *
   539         *  The MessageQ module itself does not use any shared memory but the
   540         *  underlying transport may use some shared memory.
   541         */
   542        SizeT sharedMemReq(Ptr sharedAddr);
   543    
   544        /*!
   545         *  ======== registerTransport ========
   546         *  Register a transport with MessageQ
   547         *
   548         *  This API is called by the transport when it is created.
   549         *
   550         *  @param(transport)   transport to register
   551         *  @param(procId)      MultiProc id that transport communicates with
   552         *  @param(priority)    priority of transport
   553         *
   554         *  @b(returns)         Whether the register was successful.
   555         */
   556        Bool registerTransport(IMessageQTransport.Handle transport, UInt16 procId,
   557            UInt priority);
   558    
   559        /*!
   560         *  ======== unregisterTransport ========
   561         *  Unregister a transport with MessageQ
   562         *
   563         *  @param(procId)      unregister transport that communicates with
   564         *                      this remote processor
   565         *  @param(priority)    priority of transport
   566         */
   567        Void unregisterTransport(UInt16 procId, UInt priority);
   568        
   569    instance:
   570      
   571        /*! 
   572         *  ISync handle used to signal IO completion 
   573         *
   574         *  The ISync instance is used in the {@link #get} and {@link #put}.
   575         *  The {@link xdc.runtime.knl.ISync#signal} is called as part
   576         *  of the {@link #put} call.  The {@link xdc.runtime.knl.ISync#wait} is 
   577         *  called in the {@link #get} if there are no messages present.
   578         */
   579        config ISync.Handle synchronizer = null;
   580        
   581        /*! @_nodoc
   582         *  ======== create ========
   583         *  Create a message queue
   584         *
   585         *  @param(name)         Name of the message queue.
   586         */
   587        create(String name);   
   588        
   589    internal:
   590        /* 
   591         *  The following describes the usage of the flag field     
   592         *  ---------------------------------
   593         *  |V V V|T|     reserved      |P P|
   594         *  ---------------------------------
   595         *   E D C B A 0 9 8 7 6 5 4 3 2 1 0
   596         *     
   597         *  V = version
   598         *  P = priority
   599         *  T = trace flag
   600         */
   601    
   602        /*! Mask to extract version setting */
   603        const UInt VERSIONMASK = 0xE000;
   604        
   605        /*! Version setting */
   606        const UInt HEADERVERSION = 0x2000;
   607        
   608        /*! Mask to extract Trace setting */
   609        const UInt TRACEMASK = 0x1000;
   610        
   611        /*! Shift for Trace setting */
   612        const UInt TRACESHIFT = 12;
   613           
   614        /*!
   615         *  Mask to extract priority setting.
   616         *  This is needed here for ROV but must match
   617         *  the value defined in ti/ipc/MessageQ.h
   618         */
   619        const UInt PRIORITYMASK = 0x3;
   620        
   621        /*! Mask to extract priority setting */
   622        const UInt TRANSPORTPRIORITYMASK = 0x1;
   623            
   624         /*! return code for Instance_init */
   625        const Int PROXY_FAILURE = 1;
   626    
   627        /* 
   628         *  Used to denote a message that was initialized 
   629         *  with the MessageQ_staticMsgInit function.
   630         */
   631        const UInt16 STATICMSG = 0xFFFF;
   632    
   633        /*! Required first field in every message */
   634        @Opaque struct MsgHeader {
   635            Bits32       reserved0;         /* reserved for List.elem->next */
   636            Bits32       reserved1;         /* reserved for List.elem->prev */
   637            Bits32       msgSize;           /* message size                 */
   638            Bits16       flags;             /* bitmask of different flags   */
   639            Bits16       msgId;             /* message id                   */
   640            Bits16       dstId;             /* destination processor id     */
   641            Bits16       dstProc;           /* destination processor        */
   642            Bits16       replyId;           /* reply id                     */
   643            Bits16       replyProc;         /* reply processor              */
   644            Bits16       srcProc;           /* source processor             */
   645            Bits16       heapId;            /* heap id                      */
   646            Bits16       seqNum;            /* sequence number              */
   647            Bits16       reserved;          /* reserved                     */
   648        };
   649        
   650        struct HeapEntry {
   651            IHeap.Handle  heap;
   652            UInt16        heapId;
   653        };
   654        
   655        struct TransportEntry {
   656            IMessageQTransport.Handle  transport;
   657            UInt16             procId;
   658        };
   659        
   660        /*! 
   661         *  ======== nameSrvPrms ========
   662         *  This Params object is used for temporary storage of the
   663         *  module wide parameters that are for setting the NameServer instance.
   664         */
   665        metaonly config NameServer.Params nameSrvPrms;
   666        
   667        /*! 
   668         *  Statically registered heaps
   669         *
   670         *  This configuration parameter allows the static registeration
   671         *  of heaps. The index of the array corresponds to the heapId.     
   672         */
   673        metaonly config HeapEntry staticHeaps[];
   674        
   675        /*! 
   676         *  Statically registered transports
   677         *
   678         *  This configuration parameter allows the static registeration
   679         *  of transports. The index of the array corresponds to the procId.     
   680         */
   681        metaonly config TransportEntry staticTransports[];
   682        
   683        /*!
   684         *  Allows for the number of dynamically created message queues to grow.
   685         */
   686        UInt16 grow(Object *obj, Error.Block *eb);
   687      
   688        struct Instance_State {
   689            QueueId         queue;        /* Unique id                 */
   690            ISync.Handle    synchronizer; /* completion synchronizer   */
   691            List.Object     normalList;   /* Embedded List objects     */
   692            List.Object     highList;     /* Embedded List objects     */
   693            Ptr             nsKey;
   694            SyncSem.Handle  syncSemHandle; /* for use in finalize      */
   695            Bool            unblocked;    /* Whether MessageQ is unblocked */
   696        };
   697      
   698        struct Module_State {        
   699            IMessageQTransport.Handle transports[][2];
   700            Handle               queues[];        
   701            IHeap.Handle         heaps[];        
   702            IGateProvider.Handle gate;
   703            UInt16               numQueues;
   704            UInt16               numHeaps;        
   705            NameServer.Handle    nameServer;
   706            Bool                 canFreeQueues;
   707            UInt16               seqNum;
   708    
   709        };
   710    } 
   711    /*
   712     *  @(#) ti.sdo.ipc; 1, 0, 0, 0,445; 8-10-2010 17:48:34; /db/vtree/library/trees/ipc/ipc-e23x/src/
   713     */
   714