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 * @a(WARNING)
235 * Be careful with the msgSize parameter! The 'msg' pointer passed to
236 * {@link #pend()} must point to a buffer whose size matches this msgSize
237 * parameter. {@link #pend()} does a blind copy of size 'msgSize' into
238 * the destination pointer, so the destination buffer must be big enough to
239 * handle this copy.
240 *
241 */
242 create(SizeT msgSize, UInt numMsgs);
243
244 /*!
245 * ======== heap ========
246 * The IHeap instance used for dynamic creates
247 *
248 * This heap is used only for dynamic instances is ignored for static
249 * instances.
250 */
251 config xdc.runtime.IHeap.Handle heap = null;
252
253 /*!
254 * ======== sectionName ========
255 * Section name for the buffer managed by the instance
256 *
257 * The default section is the 'dataSection' in the platform.
258 */
259 metaonly config String sectionName = null;
260
261 /*!
262 * ======== readerEvent ========
263 * Mailbox not empty event if using Events. Default is null
264 *
265 * Posted whenever a mailbox is written to.
266 * Reader task pends on this event.
267 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
268 * Semaphore.supportsEvents} has to be
269 * set to true for Mailbox to support Events.
270 */
271 config Event.Handle readerEvent = null;
272
273 /*!
274 * ======== readerEventId ========
275 * Mailbox not empty event Id if using Events. Default is 1
276 *
277 * Posted whenever a mailbox is written to.
278 * Reader task pends on this eventId.
279 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
280 * Semaphore.supportsEvents} has to be
281 * set to true for Mailbox to support Events.
282 */
283 config UInt readerEventId = 1;
284
285 /*!
286 * ======== writerEvent ========
287 * Mailbox not full event if using Events. Default is null
288 *
289 * Posted whenever a mailbox is read from.
290 * Writer task pends on this event.
291 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
292 * Semaphore.supportsEvents} has to be
293 * set to true for Mailbox to support Events.
294 */
295 config Event.Handle writerEvent = null;
296
297 /*!
298 * ======== writerEventId ========
299 * Mailbox not full event Id if using Events
300 *
301 * Posted whenever a mailbox is read from.
302 * Writer task pends on this eventId.
303 * Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
304 * Semaphore.supportsEvents} has to be
305 * set to true for Mailbox to support Events.
306 */
307 config UInt writerEventId = 1;
308
309 /*!
310 * ======== buf ========
311 * The address of the buffer used for creating messages
312 *
313 * This property is only used for dynamically created Mailboxes.
314 * If set to 'null', the messages will be allocated from the heap
315 * during runtime, otherwise the user may set this to a buffer of their
316 * creation to be used for allocating the messages.
317 *
318 * The module will split the buf into
319 * {@link ti.sysbios.knl.Mailbox#numMsgs} number of blocks (one block per
320 * Mailbox message).
321 *
322 * Please note that if the buffer is user supplied, then it is the user's
323 * responsibility to ensure that it is aligned properly and is also large
324 * enough to contain {@link ti.sysbios.knl.Mailbox#numMsgs} number of
325 * blocks. The size of each block is defined as follows:
326 * @p(code)
327 * sizeof(Mailbox_MbxElem) + msgSize
328 * @p
329 *
330 * Since the buffer must be a aligned properly, it may be necessary to
331 * 'round up' the total size of the buffer to the next multiple of the
332 * alignment for odd sized messages.
333 *
334 * Also note that if {@link ti.sysbios.BIOS#runtimeCreatesEnabled
335 * BIOS.runtimeCreatesEnabled} is set to false, then the user is required
336 * to provide this buffer when constructing the Mailbox object. If 'buf'
337 * is not set, then Mailbox_construct() will fail.
338 *
339 * @see #MbxElem
340 */
341 config Ptr buf = null;
342
343 /*!
344 * ======== bufSize ========
345 * The size of the buffer that 'buf' references
346 *
347 * This property is only used for dynamically created Mailboxes.
348 */
349 config UInt bufSize = 0;
350
351 /*!
352 * ======== getMsgSize ========
353 * Get the message size
354 */
355 SizeT getMsgSize();
356
357 /*!
358 * ======== getNumFreeMsgs ========
359 * Get the number messages available for use
360 */
361 Int getNumFreeMsgs();
362
363 /*!
364 * ======== getNumPendingMsgs ========
365 * Get the number of messages that are ready to be read
366 */
367 Int getNumPendingMsgs();
368
369 /*!
370 * ======== pend ========
371 * Wait for a message from mailbox
372 *
373 * If the mailbox is not empty, Mailbox_pend copies the first message into
374 * msg and returns TRUE. Otherwise, Mailbox_pend suspends the execution of
375 * the current task until Mailbox_post is called or the timeout expires.
376 *
377 * A timeout value of
378 * {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes
379 * the task to wait indefinitely for a message.
380 *
381 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
382 * causes Mailbox_pend to return immediately.
383 *
384 * The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
385 * should be passed to Mailbox_pend() to retrieve a message after
386 * Event_pend() is called outside of Mailbox_pend to wait on an incoming
387 * message.
388 *
389 * Mailbox_pend's return value indicates whether the mailbox was signaled
390 * successfully.
391 *
392 * @param(msg) message pointer
393 * @param(timeout) maximum duration in system clock ticks
394 * @b(returns) TRUE if successful, FALSE if timeout
395 *
396 * @a(WARNING)
397 * Be careful with the 'msg' parameter! The size of the buffer that 'msg'
398 * points to must match the 'msgSize' that was specified
399 * when the mailbox was created. This function does a blind copy of the
400 * message from the mailbox to the destination pointer, so he destination
401 * buffer must be big enough to handle this copy.
402 */
403 Bool pend(Ptr msg, UInt32 timeout);
404
405 /*!
406 * ======== post ========
407 * Post a message to mailbox
408 *
409 * Mailbox_post checks to see if there are any free message slots before
410 * copying msg into the mailbox. Mailbox_post readies the first task
411 * (if any) waiting on the mailbox. If the mailbox is full and a timeout
412 * is specified the task remains suspended until Mailbox_pend is called
413 * or the timeout expires.
414 *
415 * A timeout value of
416 * {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes
417 * the task to wait indefinitely for a free slot.
418 *
419 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
420 * causes Mailbox_post to return immediately.
421 *
422 * The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
423 * should be passed to Mailbox_post() to post a message after
424 * Event_pend() is called outside of Mailbox_post to wait on an
425 * available message buffer.
426 *
427 * Mailbox_post's return value indicates whether the msg was
428 * copied or not.
429 *
430 * @param(msg) message pointer
431 * @param(timeout) maximum duration in system clock ticks
432 * @b(returns) TRUE if successful, FALSE if timeout
433 *
434 * @a(NOTE)
435 * The operation of adding a message to the mailbox and signalling
436 * the task (if any) waiting on the mailbox is not atomic. This can
437 * result in a priority inversion with respect to message delivery.
438 * This can for example affect the order of message delivery for 2
439 * tasks with different priorities. The lower priority task's message
440 * may be delivered first while the higher priority task's message
441 * may not unblock the task waiting on the mailbox until the lower
442 * priority task resumes and completes its Mailbox_post() call.
443 */
444 Bool post(Ptr msg, UInt32 timeout);
445
446 internal:
447
448 Void cleanQue(Queue.Handle obj);
449
450 451 452 453
454 Int postInit(Object *obj, SizeT blockSize);
455
456 config UInt maxTypeAlign;
457
458
459 struct Instance_State {
460 xdc.runtime.IHeap.Handle heap;
461 SizeT msgSize;
462 UInt numMsgs;
463 Ptr buf;
464 Queue.Object dataQue;
465 Queue.Object freeQue;
466 Semaphore.Object dataSem;
467 Semaphore.Object freeSem;
468 UInt numFreeMsgs;
469 Char allocBuf[];
470 };
471 }