1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32 33 34 35
36 package ti.sysbios.knl;
37
38 import xdc.rov.ViewInfo;
39
40 import xdc.runtime.IHeap;
41
42 /*!
43 * ======== Mailbox ========
44 * Mailbox Manager
45 *
46 * The Mailbox module makes available a set of functions that manipulate
47 * mailbox objects accessed through handles of type Mailbox_Handle.
48 *
49 * {@link #pend()} is used to wait for a message from a mailbox.
50 * The timeout parameter to Mailbox_pend allows the task to wait until a
51 * timeout specified in terms of system clock ticks.
52 * A timeout value of {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER}
53 * causes the task to wait indefinitely for a message.
54 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT BIOS_NO_WAIT}
55 * causes Mailbox_pend to return immediately.
56 * Mailbox_pend's return value indicates whether the mailbox was signaled
57 * successfully.
58 *
59 * When a Mailbox has been configured with a {@link #readerEvent} Event
60 * object and a task has returned from {@link Event#pend()} with the
61 * corresponding {@link #readerEventId}, then BIOS_NO_WAIT
62 * should be passed to Mailbox_pend() to retrieve the message.
63 *
64 * NOTE: Since only a single reader can pend on a {@link #readerEvent}
65 * Event object,
66 * a Mailbox configured with a {@link #readerEvent} Event object does not
67 * support multiple readers.
68 *
69 * {@link #post()} is used to send a message to a mailbox.
70 * The timeout parameter to Mailbox_post specifies the amount of time the
71 * calling task waits if the mailbox is full.
72 *
73 * When a Mailbox has been configured with a {@link #writerEvent} Event
74 * object and a task has returned from {@link Event#pend()} with the
75 * corresponding {@link #writerEventId}, then BIOS_NO_WAIT
76 * should be passed to Mailbox_post() knowing that the message
77 * will be successfully posted.
78 *
79 * NOTE: Since only a single writer can pend on a {@link #writerEvent}
80 * Event object,
81 * a Mailbox configured with a {@link #writerEvent} Event object does not
82 * support multiple writers.
83 *
84 * @p(html)
85 * <h3> Calling Context </h3>
86 * <table border="1" cellpadding="3">
87 * <colgroup span="1"></colgroup> <colgroup span="5" align="center">
88 * </colgroup>
89 *
90 * <tr><th> Function </th><th> Hwi </th><th> Swi </th>
91 * <th> Task </th><th> Main </th><th> Startup </th></tr>
92 * <!-- -->
93 * <tr><td> {@link #Params_init} </td><td> Y </td><td> Y </td>
94 * <td> Y </td><td> Y </td><td> Y </td></tr>
95 * <tr><td> {@link #construct} </td><td> N </td><td> N </td>
96 * <td> Y </td><td> Y </td><td> N </td></tr>
97 * <tr><td> {@link #create} </td><td> N </td><td> N </td>
98 * <td> Y </td><td> Y </td><td> N </td></tr>
99 * <tr><td> {@link #delete} </td><td> N </td><td> N </td>
100 * <td> Y </td><td> Y </td><td> N </td></tr>
101 * <tr><td> {@link #destruct} </td><td> N </td><td> N </td>
102 * <td> Y </td><td> Y </td><td> N </td></tr>
103 * <tr><td> {@link #getNumFreeMsgs} </td><td> Y </td><td> Y </td>
104 * <td> Y </td><td> N </td><td> N </td></tr>
105 * <tr><td> {@link #getNumPendingMsgs} </td><td> Y </td><td> Y </td>
106 * <td> Y </td><td> N </td><td> N </td></tr>
107 * <tr><td> {@link #pend} </td><td> N* </td><td> N* </td>
108 * <td> Y </td><td> N* </td><td> N </td></tr>
109 * <tr><td> {@link #post} </td><td> N* </td><td> N* </td>
110 * <td> Y </td><td> N* </td><td> N </td></tr>
111 * <tr><td colspan="6"> Definitions: (N* means OK to call iff the timeout
112 * parameter is set to '0'.)<br />
113 * <ul>
114 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
115 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
116 * <li> <b>Task</b>: API is callable from a Task thread. </li>
117 * <li> <b>Main</b>: API is callable during any of these phases: </li>
118 * <ul>
119 * <li> In your module startup after this module is started
120 * (e.g. Mailbox_Module_startupDone() returns TRUE). </li>
121 * <li> During xdc.runtime.Startup.lastFxns. </li>
122 * <li> During main().</li>
123 * <li> During BIOS.startupFxns.</li>
124 * </ul>
125 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
126 * <ul>
127 * <li> During xdc.runtime.Startup.firstFxns.</li>
128 * <li> In your module startup before this module is started
129 * (e.g. Mailbox_Module_startupDone() returns FALSE).</li>
130 * </ul>
131 * </ul>
132 * </td></tr>
133 *
134 * </table>
135 * @p
136 */
137
138 @DirectCall
139 @ModuleStartup
140 @InstanceFinalize
141 @InstanceInitError
142 @InstanceInitStatic
143
144 module Mailbox
145 {
146 /*!
147 * ======== BasicView ========
148 * @_nodoc
149 */
150 metaonly struct BasicView {
151 String label;
152 SizeT msgSize;
153 UInt numMsgs;
154 }
155
156 /*!
157 * ======== DetailedView ========
158 * @_nodoc
159 */
160 metaonly struct DetailedView {
161 String label;
162 SizeT msgSize;
163 UInt numMsgs;
164 UInt curNumMsgs;
165 UInt freeSlots;
166 String pendQueue[];
167 String postQueue[];
168 }
169
170 /*!
171 * ======== rovViewInfo ========
172 * @_nodoc
173 */
174 @Facet
175 metaonly config ViewInfo.Instance rovViewInfo =
176 ViewInfo.create({
177 viewMap: [
178 [
179 'Basic',
180 {
181 type: ViewInfo.INSTANCE,
182 viewInitFxn: 'viewInitBasic',
183 structName: 'BasicView'
184 }
185 ],
186 [
187 'Detailed',
188 {
189 type: ViewInfo.INSTANCE,
190 viewInitFxn: 'viewInitDetailed',
191 structName: 'DetailedView'
192 }
193 ]
194 ]
195 });
196
197 /*!
198 * ======== MbxElem ========
199 * The header used to save each Mailbox message
200 *
201 * Mailbox messages are stored in a queue that requires a header in
202 * front of each message. This structure defines that header and its
203 * size must be factored into the total data size requirements for a
204 * mailbox instance.
205 */
206 struct MbxElem {
207 Queue.Elem elem;
208 };
209
210 /*!
211 * ======== A_invalidBufSize ========
212 * Assert raised when the bufSize parameter is too small
213 *
214 * This assert is raised when bufSize is too small to handle
215 * (size of messages + sizeof(MbxElem)) * number of messages.
216 * See {@link ti.sysbios.knl.MailBox#buf} for more information on the buf
217 * parameter.
218 */
219 config xdc.runtime.Assert.Id A_invalidBufSize =
220 {msg: "Mailbox_create's bufSize parameter is invalid (too small)"};
221
222 instance:
223
224 /*!
225 * ======== create ========
226 * Create a mailbox
227 *
228 * Mailbox_create creates a mailbox object which is initialized to contain
229 * numMsgs messages of size msgSize.
230 *
231 * @param(msgSize) size of message
232 * @param(numMsgs) length of mailbox
233 */
234 create(SizeT msgSize, UInt numMsgs);
235
236 /*!
237 * ======== heap ========
238 * The IHeap instance used for dynamic creates
239 *
240 * This heap is used only for dynamic instances is ignored for static
241 * instances.
242 */
243 config xdc.runtime.IHeap.Handle heap = null;
244
245 /*!
246 * ======== sectionName ========
247 * Section name for the buffer managed by the instance
248 *
249 * The default section is the 'dataSection' in the platform.
250 */
251 metaonly config String sectionName = null;
252
253 /*!
254 * ======== readerEvent ========
255 * Mailbox not empty event if using Events. Default is null
256 *
257 * Posted whenever a mailbox is written to.
258 * Reader task pends on this event.
259 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
260 * Semaphore.supportsEvents} has to be
261 * set to true for Mailbox to support Events.
262 */
263 config Event.Handle readerEvent = null;
264
265 /*!
266 * ======== readerEventId ========
267 * Mailbox not empty event Id if using Events. Default is 1
268 *
269 * Posted whenever a mailbox is written to.
270 * Reader task pends on this eventId.
271 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
272 * Semaphore.supportsEvents} has to be
273 * set to true for Mailbox to support Events.
274 */
275 config UInt readerEventId = 1;
276
277 /*!
278 * ======== writerEvent ========
279 * Mailbox not full event if using Events. Default is null
280 *
281 * Posted whenever a mailbox is read from.
282 * Writer task pends on this event.
283 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
284 * Semaphore.supportsEvents} has to be
285 * set to true for Mailbox to support Events.
286 */
287 config Event.Handle writerEvent = null;
288
289 /*!
290 * ======== writerEventId ========
291 * Mailbox not full event Id if using Events
292 *
293 * Posted whenever a mailbox is read from.
294 * Writer task pends on this eventId.
295 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
296 * Semaphore.supportsEvents} has to be
297 * set to true for Mailbox to support Events.
298 */
299 config UInt writerEventId = 1;
300
301 /*!
302 * ======== buf ========
303 * The address of the buffer used for creating messages
304 *
305 * This property is only used for dynamically created Mailboxes.
306 * If set to 'null', the messages will be allocated from the heap
307 * during runtime, otherwise the user may set this to a buffer of their
308 * creation to be used for allocating the messages.
309 *
310 * The module will split the buf into
311 * {@link ti.sysbios.knl.Mailbox#numMsgs} number of blocks (one block per
312 * Mailbox message).
313 *
314 * Please note that if the buffer is user supplied, then it is the user's
315 * responsibility to ensure that it is aligned properly and is also large
316 * enough to contain {@link ti.sysbios.knl.Mailbox#numMsgs} number of
317 * blocks. The size of each block is defined as follows:
318 * @p(code)
319 * sizeof(Mailbox_MbxElem) + msgSize
320 * @p
321 *
322 * Since the buffer must be a aligned properly, it may be necessary to
323 * 'round up' the total size of the buffer to the next multiple of the
324 * alignment for odd sized messages.
325 *
326 * Also note that if {@link ti.sysbios.BIOS#runtimeCreatesEnabled
327 * BIOS.runtimeCreatesEnabled} is set to false, then the user is required
328 * to provide this buffer when constructing the Mailbox object. If 'buf'
329 * is not set, then Mailbox_construct() will fail.
330 *
331 * @see #MbxElem
332 */
333 config Ptr buf = null;
334
335 /*!
336 * ======== bufSize ========
337 * The size of the buffer that 'buf' references
338 *
339 * This property is only used for dynamically created Mailboxes.
340 */
341 config UInt bufSize = 0;
342
343 /*!
344 * ======== getMsgSize ========
345 * Get the message size
346 */
347 SizeT getMsgSize();
348
349 /*!
350 * ======== getNumFreeMsgs ========
351 * Get the number messages available for use
352 */
353 Int getNumFreeMsgs();
354
355 /*!
356 * ======== getNumPendingMsgs ========
357 * Get the number of messages that are ready to be read
358 */
359 Int getNumPendingMsgs();
360
361 /*!
362 * ======== pend ========
363 * Wait for a message from mailbox
364 *
365 * If the mailbox is not empty, Mailbox_pend copies the first message into
366 * msg and returns TRUE. Otherwise, Mailbox_pend suspends the execution of
367 * the current task until Mailbox_post is called or the timeout expires.
368 *
369 * A timeout value of
370 * {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes
371 * the task to wait indefinitely for a message.
372 *
373 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
374 * causes Mailbox_pend to return immediately.
375 *
376 * The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
377 * should be passed to Mailbox_pend() to retrieve a message after
378 * Event_pend() is called outside of Mailbox_pend to wait on an incoming
379 * message.
380 *
381 * Mailbox_pend's return value indicates whether the mailbox was signaled
382 * successfully.
383 *
384 * @a(Event Object Note)
385 * If the Mailbox object has been configured with an embedded readerEvent
386 * Event object, then prior to returnig from this function, the Event
387 * object's state is updated to reflect whether messages are available
388 * in the Mailbox after the current message is removed.
389 * If there are no more messages available, then the readerEventId is
390 * cleared in the Event object. If more messages are available,
391 * then the readerEventId is set in the Event object.
392 *
393 * @param(msg) message pointer
394 * @param(timeout) maximum duration in system clock ticks
395 * @b(returns) TRUE if successful, FALSE if timeout
396 *
397 * @a(WARNING)
398 * Be careful with the 'msg' parameter! The size of the buffer that 'msg'
399 * points to must match the 'msgSize' that was specified
400 * when the mailbox was created. This function does a blind copy of the
401 * message from the mailbox to the destination pointer, so the destination
402 * buffer must be big enough to handle this copy.
403 */
404 Bool pend(Ptr msg, UInt32 timeout);
405
406 /*!
407 * ======== post ========
408 * Post a message to mailbox
409 *
410 * Mailbox_post checks to see if there are any free message slots before
411 * copying msg into the mailbox. Mailbox_post readies the first task
412 * (if any) waiting on the mailbox. If the mailbox is full and a timeout
413 * is specified the task remains suspended until Mailbox_pend is called
414 * or the timeout expires.
415 *
416 * A timeout value of
417 * {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes
418 * the task to wait indefinitely for a free slot.
419 *
420 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
421 * causes Mailbox_post to return immediately.
422 *
423 * The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
424 * should be passed to Mailbox_post() to post a message after
425 * Event_pend() is called outside of Mailbox_post to wait on an
426 * available message buffer.
427 *
428 * Mailbox_post's return value indicates whether the msg was
429 * copied or not.
430 *
431 * @a(Event Object Note)
432 * If the Mailbox object has been configured with an embedded writerEvent
433 * Event object, then prior to returnig from this function, the Event
434 * object's state is updated to reflect whether more messages can be
435 * posted to the Mailbox after the current message has been posted.
436 * If no more room is available, then the writerEventId is
437 * cleared in the Event object. If more room is available,
438 * then the writerEventId is set in the Event object.
439 *
440 * @param(msg) message pointer
441 * @param(timeout) maximum duration in system clock ticks
442 * @b(returns) TRUE if successful, FALSE if timeout
443 *
444 * @a(NOTE)
445 * The operation of adding a message to the mailbox and signalling
446 * the task (if any) waiting on the mailbox is not atomic. This can
447 * result in a priority inversion with respect to message delivery.
448 * This can for example affect the order of message delivery for 2
449 * tasks with different priorities. The lower priority task's message
450 * may be delivered first while the higher priority task's message
451 * may not unblock the task waiting on the mailbox until the lower
452 * priority task resumes and completes its Mailbox_post() call.
453 */
454 Bool post(Ptr msg, UInt32 timeout);
455
456 internal:
457
458 Void cleanQue(Queue.Handle obj);
459
460 461 462 463
464 Int postInit(Object *obj, SizeT blockSize);
465
466 config UInt maxTypeAlign;
467
468
469 struct Instance_State {
470 xdc.runtime.IHeap.Handle heap;
471 SizeT msgSize;
472 UInt numMsgs;
473 Ptr buf;
474 Queue.Object dataQue;
475 Queue.Object freeQue;
476 Semaphore.Object dataSem;
477 Semaphore.Object freeSem;
478 UInt numFreeMsgs;
479 Char allocBuf[];
480 };
481 }