1 /*
2 * Copyright (c) 2012-2013, 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 */
37 package ti.sdo.ipc;
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;
47 import ti.sysbios.syncs.SyncSem;
49 import ti.sdo.ipc.interfaces.IMessageQTransport;
50 import ti.sdo.utils.NameServer;
51 import ti.sdo.utils.List;
53 import xdc.rov.ViewInfo;
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 ti.sdo.ipc.interfaces.IMessageQTransport} instances.
152 * MessageQ supports a high priority and a normal priority transport between
153 * any two 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 */
159 @ModuleStartup
160 @InstanceInitError
161 @InstanceFinalize
163 module MessageQ
164 {
165 /*!
166 * ======== QueuesView ========
167 * @_nodoc
168 */
169 metaonly struct QueuesView {
170 String name;
171 UInt queueId;
172 }
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 }
191 /*!
192 * ======== ModuleView ========
193 * @_nodoc
194 */
195 metaonly struct ModuleView {
196 String heaps[];
197 String gate;
198 UInt16 nextSeqNum;
199 }
201 /*!
202 * ======== rovViewInfo ========
203 * @_nodoc
204 */
205 @Facet
206 metaonly config xdc.rov.ViewInfo.Instance rovViewInfo =
207 xdc.rov.ViewInfo.create({
208 viewMap: [
209 ['Queues',
210 {
211 type: xdc.rov.ViewInfo.INSTANCE,
212 viewInitFxn: 'viewInitQueues',
213 structName: 'QueuesView'
214 }
215 ],
216 ['Messages',
217 {
218 type: xdc.rov.ViewInfo.INSTANCE_DATA,
219 viewInitFxn: 'viewInitMessages',
220 structName: 'MessagesView'
221 }
222 ],
223 ['Module',
224 {
225 type: xdc.rov.ViewInfo.MODULE,
226 viewInitFxn: 'viewInitModule',
227 structName: 'ModuleView'
228 }
229 ]
230 ]
231 });
233 /*!
234 * ======== LM_setTrace ========
235 * Logged when setting the trace flag on a message
236 *
237 * This is logged when tracing on a message is set via
238 * {@link #setMsgTrace}.
239 */
240 config Log.Event LM_setTrace = {
241 mask: Diags.USER1,
242 msg: "LM_setTrace: Message 0x%x (seqNum = %d, srcProc = %d) traceFlag = %d"
243 };
245 /*!
246 * ======== LM_alloc ========
247 * Logged when allocating a message
248 *
249 * When the {@link #traceFlag} is true, all message allocations
250 * are logged.
251 */
252 config Log.Event LM_alloc = {
253 mask: Diags.USER1,
254 msg: "LM_alloc: Message 0x%x (seqNum = %d, srcProc = %d) was allocated"
255 };
257 /*!
258 * ======== LM_staticMsgInit ========
259 * Logged when statically initializing a message
260 *
261 * When the {@link #traceFlag} is true, all messages that
262 * are statically initialized via {@link #staticMsgInit} are logged.
263 */
264 config Log.Event LM_staticMsgInit = {
265 mask: Diags.USER1,
266 msg: "LM_staticMsgInit: Message 0x%x (seqNum = %d, srcProc = %d) was set in MessageQ_staticMsgInit"
267 };
269 /*!
270 * ======== LM_free ========
271 * Logged when freeing a message
272 *
273 * When the {@link #traceFlag} is true, all freeing of messages
274 * are logged. If an individual message's tracing was enabled
275 * via {@link #setMsgTrace}, the MessageQ_free is also logged.
276 */
277 config Log.Event LM_free = {
278 mask: Diags.USER1,
279 msg: "LM_free: Message 0x%x (seqNum = %d, srcProc = %d) was freed"
280 };
282 /*!
283 * ======== LM_putLocal ========
284 * Logged when a message is placed onto a local queue
285 *
286 * When the {@link #traceFlag} is true, all putting of messages
287 * are logged. If an individual message's tracing was enabled
288 * via {@link #setMsgTrace}, the MessageQ_put is also logged.
289 */
290 config Log.Event LM_putLocal = {
291 mask: Diags.USER1,
292 msg: "LM_putLocal: Message 0x%x (seqNum = %d, srcProc = %d) was placed onto queue 0x%x"
293 };
295 /*!
296 * ======== LM_putRemote ========
297 * Logged when a message is given to a transport
298 *
299 * When the {@link #traceFlag} is true, all putting of messages
300 * to a transport are logged. If an individual message's tracing
301 * was enabled via {@link #setMsgTrace}, the MessageQ_put is
302 * also logged.
303 */
304 config Log.Event LM_putRemote = {
305 mask: Diags.USER1,
306 msg: "LM_putRemote: Message 0x%x (seqNum = %d, srcProc = %d) was given to processor %d transport"
307 };
309 /*!
310 * ======== LM_rcvByTransport ========
311 * Logged when a transport receives an incoming message
312 *
313 * When the {@link #traceFlag} is true, all incoming messages
314 * are logged. If an individual message's tracing
315 * was enabled via {@link #setMsgTrace}, the receiving of a message is
316 * also logged.
317 */
318 config Log.Event LM_rcvByTransport = {
319 mask: Diags.USER1,
320 msg: "LM_rcvByTransport: Message 0x%x (seqNum = %d, srcProc = %d) was received"
321 };
323 /*!
324 * ======== LM_get ========
325 * Logged when a message is received off the queue
326 *
327 * When the {@link #traceFlag} is true, all getting of messages
328 * are logged. If an individual message's tracing
329 * was enabled via {@link #setMsgTrace}, the MessageQ_get is
330 * also logged.
331 */
332 config Log.Event LM_get = {
333 mask: Diags.USER1,
334 msg: "LM_get: Message 0x%x (seqNum = %d, srcProc = %d) was received by queue 0x%x"
335 };
337 /*! MessageQ ID */
338 typedef UInt32 QueueId;
340 /*!
341 * ======== SetupTransportProxy ========
342 * MessageQ transport setup proxy
343 */
344 proxy SetupTransportProxy inherits ti.sdo.ipc.interfaces.ITransportSetup;
346 /*!
347 * Message priority values. These must match the values defined in
348 * ti/ipc/MessageQ.h but are needed here for ROV.
349 */
350 const UInt NORMALPRI = 0;
351 const UInt HIGHPRI = 1;
352 const UInt RESERVEDPRI = 2;
353 const UInt URGENTPRI = 3;
355 /*!
356 * Assert raised when calling API with wrong handle
357 *
358 * Some APIs can only be called with an opened handle (e.g.
359 * {@link #close}. Some can only be called with a created handle
360 * (e.g. {@link #get}).
361 */
362 config Assert.Id A_invalidContext = {
363 msg: "A_invalidContext: Cannot call with an open/create handle"
364 };
366 /*!
367 * Assert raised when attempting to free a static message
368 */
369 config Assert.Id A_cannotFreeStaticMsg = {
370 msg: "A_cannotFreeStaticMsg: Cannot call MessageQ_free with static msg"
371 };
373 /*!
374 * Assert raised when an invalid message is supplied
375 */
376 config Assert.Id A_invalidMsg = {
377 msg: "A_invalidMsg: Invalid message"
378 };
380 /*!
381 * Assert raised when an invalid queueId is supplied
382 */
383 config Assert.Id A_invalidQueueId = {
384 msg: "A_invalidQueueId: Invalid queueId is used"
385 };
387 /*!
388 * Assert raised when using an invalid heapId
389 */
390 config Assert.Id A_heapIdInvalid = {
391 msg: "A_heapIdInvalid: heapId is invalid"
392 };
394 /*!
395 * Assert raised when using an invalid procId
396 */
397 config Assert.Id A_procIdInvalid = {
398 msg: "A_procIdInvalid: procId is invalid"
399 };
401 /*!
402 * Assert raised for an invalid MessageQ object
403 */
404 config Assert.Id A_invalidObj = {
405 msg: "A_invalidObj: an invalid obj is used"
406 };
408 /*!
409 * Assert raised for an invalid parameter
410 */
411 config Assert.Id A_invalidParam = {
412 msg: "A_invalidParam: an invalid parameter was passed in"
413 };
415 /*!
416 * Assert raised when attempting to send a message to a core
417 * where a transport has not been registered.
418 */
419 config Assert.Id A_unregisteredTransport = {
420 msg: "A_unregisteredTransport: transport is not registered"
421 };
423 /*!
424 * Assert raised when attempting to unblock a remote MessageQ or one that
425 * has been configured with a non-blocking synchronizer
426 */
427 config Assert.Id A_invalidUnblock = {
428 msg: "A_invalidUnblock: Trying to unblock a remote MessageQ or a queue with non-blocking synchronizer"
429 };
431 /*!
432 * Error raised if all the message queue objects are taken
433 */
434 config Error.Id E_maxReached = {
435 msg: "E_maxReached: All objects in use. MessageQ.maxRuntimeEntries is %d"
436 };
438 /*!
439 * Error raised when heapId has not been registered
440 */
441 config Error.Id E_unregisterHeapId = {
442 msg: "E_unregisterHeapId: Heap id %d not registered"
443 };
445 /*!
446 * Error raised in a create call when a name fails to be added
447 * to the NameServer table. This can be because the name already
448 * exists, the table has reached its max length, or out of memory.
449 */
450 config Error.Id E_nameFailed = {
451 msg: "E_nameFailed: '%s' name failed to be added to NameServer"
452 };
454 /*!
455 * Trace setting
456 *
457 * This flag allows the configuration of the default module trace
458 * settings.
459 */
460 config Bool traceFlag = false;
462 /*!
463 * Number of heapIds in the system
464 *
465 * This allows MessageQ to pre-allocate the heaps table.
466 * The heaps table is used when registering heaps.
467 *
468 * There is no default heap, so unless the system is only using
469 * {@link #staticMsgInit}, the application must register a heap.
470 */
471 config UInt16 numHeaps = 8;
473 /*!
474 * Maximum number of MessageQs that can be dynamically created
475 */
476 config UInt maxRuntimeEntries = NameServer.ALLOWGROWTH;
478 /*!
479 * Gate used to make the name table thread safe
480 *
481 * This gate is used when accessing the name table during
482 * a {@link #create}, {@link #delete}, and {@link #open}.
483 *
484 * This gate is also used to protect MessageQ when growing
485 * internal tables in the {@link #create}.
486 *
487 * The table is in local memory, not shared memory. So a
488 * single processor gate will work.
489 *
490 * The default will be {@link xdc.runtime.knl.GateThread}
491 * instance.
492 */
493 config IGateProvider.Handle nameTableGate = null;
495 /*!
496 * Maximum length for Message queue names
497 */
498 config UInt maxNameLen = 32;
500 /*!
501 * Section name is used to place the names table
502 */
503 metaonly config String tableSection = null;
505 /*!
506 * ======== registerHeapMeta ========
507 * Statically register a heap with MessageQ
508 *
509 * Build error if heapId is in use.
510 *
511 * @param(heap) Heap to register
512 * @param(heapId) heapId associated with the heap
513 */
514 metaonly Void registerHeapMeta(IHeap.Handle heap, UInt16 heapId);
516 /*!
517 * ======== registerTransportMeta ========
518 * Statically register a transport with MessageQ
519 *
520 * Build error if remote processor already has a transport
521 * registered.
522 *
523 * @param(transport) transport to register
524 * @param(procId) procId that transport communicaties with
525 * @param(priority) priority of transport
526 */
527 metaonly Void registerTransportMeta(IMessageQTransport.Handle transport, UInt16 procId, UInt priority);
529 /*!
530 * ======== registerTransport ========
531 * Register a transport with MessageQ
532 *
533 * This API is called by the transport when it is created.
534 *
535 * @param(transport) transport to register
536 * @param(procId) MultiProc id that transport communicates with
537 * @param(priority) priority of transport
538 *
539 * @b(returns) Whether the register was successful.
540 */
541 Bool registerTransport(IMessageQTransport.Handle transport, UInt16 procId,
542 UInt priority);
544 /*!
545 * ======== unregisterTransport ========
546 * Unregister a transport with MessageQ
547 *
548 * @param(procId) unregister transport that communicates with
549 * this remote processor
550 * @param(priority) priority of transport
551 */
552 Void unregisterTransport(UInt16 procId, UInt priority);
554 instance:
556 /*!
557 * ISync handle used to signal IO completion
558 *
559 * The ISync instance is used in the {@link #get} and {@link #put}.
560 * The {@link xdc.runtime.knl.ISync#signal} is called as part
561 * of the {@link #put} call. The {@link xdc.runtime.knl.ISync#wait} is
562 * called in the {@link #get} if there are no messages present.
563 */
564 config ISync.Handle synchronizer = null;
566 /*! @_nodoc
567 * ======== create ========
568 * Create a message queue
569 *
570 * @param(name) Name of the message queue.
571 */
572 create(String name);
574 internal:
575 /*
576 * The following describes the usage of the flag field
577 * ---------------------------------
578 * |V V V|T| reserved |P P|
579 * ---------------------------------
580 * E D C B A 0 9 8 7 6 5 4 3 2 1 0
581 *
582 * V = version
583 * P = priority
584 * T = trace flag
585 */
587 /*! Mask to extract version setting */
588 const UInt VERSIONMASK = 0xE000;
590 /*! Version setting */
591 const UInt HEADERVERSION = 0x2000;
593 /*! Mask to extract Trace setting */
594 const UInt TRACEMASK = 0x1000;
596 /*! Shift for Trace setting */
597 const UInt TRACESHIFT = 12;
599 /*!
600 * Mask to extract priority setting.
601 * This is needed here for ROV but must match
602 * the value defined in ti/ipc/MessageQ.h
603 */
604 const UInt PRIORITYMASK = 0x3;
606 /*! Mask to extract priority setting */
607 const UInt TRANSPORTPRIORITYMASK = 0x1;
609 /*! return code for Instance_init */
610 const Int PROXY_FAILURE = 1;
612 /*
613 * Used to denote a message that was initialized
614 * with the MessageQ_staticMsgInit function.
615 */
616 const UInt16 STATICMSG = 0xFFFF;
618 /*! Required first field in every message */
619 @Opaque struct MsgHeader {
620 Bits32 reserved0; /* reserved for List.elem->next */
621 Bits32 reserved1; /* reserved for List.elem->prev */
622 Bits32 msgSize; /* message size */
623 Bits16 flags; /* bitmask of different flags */
624 Bits16 msgId; /* message id */
625 Bits16 dstId; /* destination processor id */
626 Bits16 dstProc; /* destination processor */
627 Bits16 replyId; /* reply id */
628 Bits16 replyProc; /* reply processor */
629 Bits16 srcProc; /* source processor */
630 Bits16 heapId; /* heap id */
631 Bits16 seqNum; /* sequence number */
632 Bits16 reserved; /* reserved */
633 };
635 struct HeapEntry {
636 IHeap.Handle heap;
637 UInt16 heapId;
638 };
640 struct TransportEntry {
641 IMessageQTransport.Handle transport;
642 UInt16 procId;
643 };
645 /*!
646 * ======== nameSrvPrms ========
647 * This Params object is used for temporary storage of the
648 * module wide parameters that are for setting the NameServer instance.
649 */
650 metaonly config NameServer.Params nameSrvPrms;
652 /*!
653 * Statically registered heaps
654 *
655 * This configuration parameter allows the static registeration
656 * of heaps. The index of the array corresponds to the heapId.
657 */
658 metaonly config HeapEntry staticHeaps[];
660 /*!
661 * Statically registered transports
662 *
663 * This configuration parameter allows the static registeration
664 * of transports. The index of the array corresponds to the procId.
665 */
666 metaonly config TransportEntry staticTransports[];
668 /*!
669 * Allows for the number of dynamically created message queues to grow.
670 */
671 UInt16 grow(Object *obj, Error.Block *eb);
673 struct Instance_State {
674 QueueId queue; /* Unique id */
675 ISync.Handle synchronizer; /* completion synchronizer */
676 List.Object normalList; /* Embedded List objects */
677 List.Object highList; /* Embedded List objects */
678 Ptr nsKey; /* unique NameServer key */
679 SyncSem.Handle syncSemHandle;/* for use in finalize */
680 Bool unblocked; /* Whether MessageQ is unblocked */
681 };
683 struct Module_State {
684 IMessageQTransport.Handle transports[][2];
685 Handle queues[];
686 IHeap.Handle heaps[];
687 IGateProvider.Handle gate;
688 UInt16 numQueues;
689 UInt16 numHeaps;
690 NameServer.Handle nameServer;
691 Bool canFreeQueues;
692 UInt16 seqNum;
693 };
694 }