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
37 package ti.sysbios.knl;
38
39 import xdc.rov.ViewInfo;
40
41 import xdc.runtime.Diags;
42 import xdc.runtime.Log;
43 import xdc.runtime.Assert;
44 import xdc.runtime.Error;
45
46 import ti.sysbios.knl.Queue;
47 import ti.sysbios.knl.Task;
48 import ti.sysbios.knl.Clock;
49
50 /*!
51 * ======== Semaphore ========
52 * Semaphore Manager
53 *
54 * The Semaphore manager makes available a set of functions that manipulate
55 * semaphore objects. Semaphores can be used for task synchronization and
56 * mutual exclusion.
57 *
58 * Semaphores can be counting semaphores or binary semaphores. Counting
59 * semaphores keep track of the number of times the semaphore has been posted
60 * with post(). This is useful, for example, if you have a group of resources
61 * that are shared between tasks. Such tasks might call pend() to see if a
62 * resource is available before using one.
63 *
64 * Binary semaphores can have only two states: available (count = 1) and
65 * unavailable (count = 0). They can be used to share a single resource
66 * between tasks. They can also be used for a basic signaling mechanism,
67 * where the semaphore can be posted multiple times. Binary semaphores do
68 * not keep track of the count; they simply track whether the semaphore has
69 * been posted or not.
70 *
71 * See {@link #getCount Semaphore_getCount()} for more details of the 'count'
72 * behavior.
73 *
74 * The Mailbox module uses a counting semaphore internally to manage the
75 * count of free (or full) mailbox elements. Another example of a counting
76 * semaphore is an ISR that might fill multiple buffers of data for
77 * consumption by a task. After filling each buffer, the ISR puts the buffer on
78 * a queue and calls post(). The task waiting for the data calls pend(), which
79 * simply decrements the semaphore count and returns or blocks if the count is
80 * 0. The semaphore count thus tracks the number of full buffers available for
81 * the task.
82 *
83 * pend() is used to wait for a semaphore. The timeout parameter allows the
84 * task to wait until a timeout, wait indefinitely, or not wait at all. The
85 * return value is used to indicate if the semaphore was signaled successfully.
86 *
87 * post() is used to signal a semaphore. If a task is waiting for the
88 * semaphore, post() removes the task from the semaphore queue and puts it on
89 * the ready queue. If no tasks are waiting, post() simply increments the
90 * semaphore count and returns. For a binary semaphore the count is always
91 * set to one.
92 *
93 * @p(html)
94 * <h3> Calling Context </h3>
95 * <table border="1" cellpadding="3">
96 * <colgroup span="1"></colgroup> <colgroup span="5" align="center">
97 * </colgroup>
98 *
99 * <tr><th> Function </th><th> Hwi </th><th> Swi </th>
100 * <th> Task </th><th> Main </th><th> Startup </th></tr>
101 * <!-- -->
102 * <tr><td> {@link #Params_init} </td><td> Y </td><td> Y </td>
103 * <td> Y </td><td> Y </td><td> Y </td></tr>
104 * <tr><td> {@link #construct} </td><td> N </td><td> N </td>
105 * <td> Y </td><td> Y </td><td> N </td></tr>
106 * <tr><td> {@link #create} </td><td> N </td><td> N </td>
107 * <td> Y </td><td> Y </td><td> N </td></tr>
108 * <tr><td> {@link #delete} </td><td> N </td><td> N </td>
109 * <td> Y </td><td> Y </td><td> N </td></tr>
110 * <tr><td> {@link #destruct} </td><td> N </td><td> N </td>
111 * <td> Y </td><td> Y </td><td> N </td></tr>
112 * <tr><td> {@link #getCount} </td><td> Y </td><td> Y </td>
113 * <td> Y </td><td> Y </td><td> Y </td></tr>
114 * <tr><td> {@link #pend} </td><td> N* </td><td> N* </td>
115 * <td> Y </td><td> N* </td><td> N </td></tr>
116 * <tr><td> {@link #post} </td><td> Y </td><td> Y </td>
117 * <td> Y </td><td> Y </td><td> N </td></tr>
118 * <tr><td> {@link #registerEvent} </td><td> N </td><td> N </td>
119 * <td> Y </td><td> Y </td><td> Y </td></tr>
120 * <tr><td> {@link #reset} </td><td> N </td><td> N </td>
121 * <td> Y </td><td> Y </td><td> N </td></tr>
122 * <tr><td colspan="6"> Definitions: (N* means OK to call iff the timeout
123 * parameter is set to '0'.)<br />
124 * <ul>
125 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
126 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
127 * <li> <b>Task</b>: API is callable from a Task thread. </li>
128 * <li> <b>Main</b>: API is callable during any of these phases: </li>
129 * <ul>
130 * <li> In your module startup after this module is started
131 * (e.g. Semaphore_Module_startupDone() returns TRUE). </li>
132 * <li> During xdc.runtime.Startup.lastFxns. </li>
133 * <li> During main().</li>
134 * <li> During BIOS.startupFxns.</li>
135 * </ul>
136 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
137 * <ul>
138 * <li> During xdc.runtime.Startup.firstFxns.</li>
139 * <li> In your module startup before this module is started
140 * (e.g. Semaphore_Module_startupDone() returns FALSE).</li>
141 * </ul>
142 * </ul>
143 * </td></tr>
144 *
145 * </table>
146 * @p
147 */
148
149 @CustomHeader
150 @DirectCall
151
152 @InstanceFinalize
153 @InstanceInitStatic
154
155
156 module Semaphore
157 {
158 /*!
159 * Semaphore types.
160 *
161 * These enumerations specify the type of semaphore.
162 *
163 * Tasks wait for the semaphore in FIFO order unless the PRIORITY
164 * option is chosen.
165 *
166 * For PRIORITY semaphores, the pending task will be
167 * inserted in the waiting list before the first task that has
168 * lower priority. This ensures that tasks of equal priority will
169 * pend in FIFO order.
170 *
171 * @a(WARNING)
172 * PRIORITY semaphores have a potential to increase the interrupt
173 * latency in the system since interrupts are disabled while the list of
174 * tasks waiting on the semaphore is scanned for the proper insertion
175 * point. This is typically about a dozen instructions per waiting task.
176 * For example, if you have 10 tasks of higher priority waiting, then all
177 * 10 will be checked with interrupts disabled before the new task is
178 * entered onto the list.
179 */
180 enum Mode {
181 Mode_COUNTING = 0x0, /*! Counting (FIFO) */
182 Mode_BINARY = 0x1, /*! Binary (FIFO) */
183 Mode_COUNTING_PRIORITY = 0x2, /*! Counting (priority-based) */
184 Mode_BINARY_PRIORITY = 0x3 /*! Binary (priority-based) */
185 };
186
187 /*!
188 * ======== BasicView ========
189 * @_nodoc
190 */
191 metaonly struct BasicView {
192 String label;
193 String event;
194 String eventId;
195 String mode;
196 Int count;
197 String pendedTasks[];
198 };
199
200 /*!
201 * ======== rovViewInfo ========
202 * @_nodoc
203 */
204 @Facet
205 metaonly config ViewInfo.Instance rovViewInfo =
206 ViewInfo.create({
207 viewMap: [
208 ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}]
209 ]
210 });
211
212
213
214 /*!
215 * ======== LM_post ========
216 * Logged on calls to Semaphore_post()
217 */
218 config Log.Event LM_post = {
219 mask: Diags.USER1 | Diags.USER2,
220 msg: "LM_post: sem: 0x%x, count: %d"
221 };
222
223 /*!
224 * ======== LM_pend ========
225 * Logged on calls to Semaphore_pend()
226 */
227 config Log.Event LM_pend = {
228 mask: Diags.USER1 | Diags.USER2,
229 msg: "LM_pend: sem: 0x%x, count: %d, timeout: %d"
230 };
231
232 /*!
233 * ======== A_noEvents ========
234 * Assert raised if application uses Event but it's not supported
235 *
236 * This assertion is triggered by {@link #create} if
237 * {@link #supportsEvents} is false and an {@link ti.sysbios.knl.Event}
238 * object is passed to {@link #create}.
239 */
240 config Assert.Id A_noEvents = {
241 msg: "A_noEvents: The Event.supportsEvents flag is disabled."
242 };
243
244 /*!
245 * ======== A_invTimeout ========
246 * @_nodoc
247 * This assertion is no longer used
248 */
249 config Assert.Id A_invTimeout = {
250 msg: "A_invTimeout: Can't use BIOS_EVENT_ACQUIRED with this Semaphore."
251 };
252
253 /*!
254 * ======== A_badContext ========
255 * Assert raised if an operation is invalid in the current calling context
256 *
257 * Asserted when {@link #pend} is called with non-zero timeout from
258 * other than a Task context.
259 */
260 config Assert.Id A_badContext = {
261 msg: "A_badContext: bad calling context. Must be called from a Task."
262 };
263
264 /*!
265 * ======== A_overflow ========
266 * Assert raised if the semaphore count is incremented past 65535
267 *
268 * Asserted when Semaphore_post() has been called when the 16 bit
269 * semaphore count is at its maximum value of 65535.
270 */
271 config Assert.Id A_overflow = {
272 msg: "A_overflow: Count has exceeded 65535 and rolled over."
273 };
274
275 /*!
276 * ======== A_pendTaskDisabled ========
277 * Asserted in Sempahore_pend()
278 *
279 * Assert raised if Semaphore_pend() is called with the Task or
280 * Swi scheduler disabled.
281 */
282 config Assert.Id A_pendTaskDisabled = {
283 msg: "A_pendTaskDisabled: Cannot call Semaphore_pend() while the Task or Swi scheduler is disabled."
284 };
285
286
287
288 /*!
289 * Error raised when BIOS.mpeEnabled is TRUE and Semaphore object passed to
290 * Semaphore_construct() is not in Kernel address space. This can happen if
291 * a user Task passes a Semaphore object that resides in unprivileged
292 * memory to Semaphore_construct().
293 */
294 config Error.Id E_objectNotInKernelSpace = {
295 msg: "E_objectNotInKernelSpace: Semaphore object passed not in Kernel address space."
296 };
297
298 /*!
299 * ======== supportsEvents ========
300 * Support Semaphores with Events?
301 *
302 * The default for this parameter is false.
303 */
304 config Bool supportsEvents = false;
305
306 /*!
307 * ======== supportsPriority ========
308 * Support Task priority pend queuing?
309 *
310 * The default for this parameter is true.
311 */
312 config Bool supportsPriority = true;
313
314 /*!
315 * ======== testStaticInlines ========
316 * @_nodoc
317 * Used for code coverage testing.
318 */
319 Void testStaticInlines();
320
321 instance:
322
323 /*!
324 * ======== create ========
325 * Create a Semaphore object
326 *
327 * This function creates a new Semaphore object which is initialized to
328 * count.
329 *
330 * @param(count) initial semaphore count
331 *
332 * @a(NOTE)
333 * The "count" argument should not be a negative number as the Semaphore
334 * count is stored as a 16-bit unsigned integer inside the Semaphore
335 * object.
336 */
337 create(Int count);
338
339
340 /*!
341 * ======== event ========
342 * Event instance to use if non-NULL
343 *
344 * The default value of this parameter is null. If event is non-null:
345 * @p(blist)
346 * - Event_post(sem->event, sem->eventId) will be invoked when
347 * Semaphore_post() is called.
348 *
349 * - Event_pend(sem->event, 0, sem->eventId, timeout) will be
350 * invoked when Semaphore_pend() is called.
351 * @p
352 *
353 * @a(CONSTRAINT)
354 * The 'event' parameter is ignored if
355 * {@link #supportsEvents Semaphore.supportsEvents}
356 * is set to false.
357 */
358 config Event.Handle event = null;
359
360 /*!
361 * ======== eventId ========
362 * eventId if using Events
363 *
364 * The default for this parameters is 1.
365 *
366 * @a(CONSTRAINT)
367 * The 'eventId' parameter is ignored if
368 * {@link #supportsEvents Semaphore.supportsEvents}
369 * is set to false.
370 */
371 config UInt eventId = 1;
372
373 /*!
374 * ======== mode ========
375 * Semaphore mode
376 *
377 * When mode is BINARY, the semaphore has only two states, available
378 * and unavailable. When mode is COUNTING, the semaphore keeps track of
379 * number of times a semaphore is posted.
380 *
381 * The default for this parameter is COUNTING.
382 */
383 config Mode mode = Mode_COUNTING;
384
385 /*!
386 * ======== getCount ========
387 * Get current semaphore count
388 *
389 * This function returns the current value of the semaphore specified by
390 * the handle.
391 *
392 * A semaphore's count is incremented when Semaphore_post() is called.
393 * If configured as a binary semaphore, the count will not increment past
394 * 1. If configured as a counting semaphore, the count will continue
395 * incrementing and will rollover to zero after reaching a count of
396 * 65,535. Care must be taken in applications to avoid the rollover
397 * situation as a count of zero will always be interpreted as an empty
398 * semaphore.
399 *
400 * A semaphore's count is decremented, if non-zero, when Semaphore_pend()
401 * is called. A task will block on a semaphore if the count is zero when
402 * Semaphore_pend() is called. An empty semaphore will always have a
403 * count of zero regardless of the number of tasks that are blocked on
404 * it.
405 *
406 * @b(returns) current semaphore count
407 */
408
409 Int getCount();
410
411 /*!
412 * ======== pend ========
413 * Wait for a semaphore
414 *
415 * If the semaphore count is greater than zero (available), this function
416 * decrements the count and returns TRUE. If the semaphore count is zero
417 * (unavailable), this function suspends execution of the current task
418 * (leaving the count equal to zero) until post() is called or the
419 * timeout expires.
420 *
421 * A timeout value of
422 * {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER} causes
423 * the task to wait indefinitely for its semaphore to be posted.
424 *
425 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT BIOS_NO_WAIT}
426 * causes Semaphore_pend to return immediately.
427 *
428 * @a(Event Object Note)
429 * If the Semaphore object has been configured with an embedded Event
430 * object, then prior to returning from this function, the Event object's
431 * state is updated to reflect the new value of 'count'.
432 * If 'count' is zero, then the configured Event_Id is cleared in the
433 * Event object. If 'count' is non-zero, then the configured Event_Id
434 * is set in the Event object.
435 *
436 * @param(timeout) return after this many system time units
437 *
438 * @b(returns) TRUE if successful, FALSE if timeout
439 *
440 * @a(CONSTRAINT)
441 * It is a fatal error to invoke Semaphore_pend() with a non-zero timeout
442 * while the Task scheduler is disabled.
443 * See {@link ti.sysbios.knl.Task#disable Task_disable} for more details.
444 */
445
446 Bool pend(UInt32 timeout);
447
448 /*!
449 * ======== post ========
450 * Signal a semaphore.
451 *
452 * If any tasks are waiting on the semaphore, this function readies
453 * the first task waiting for the semaphore without incrementing
454 * the count. If no task is waiting, this function simply increments
455 * the semaphore count and returns. In the case of a binary semaphore,
456 * the count has a maximum value of one.
457 */
458
459 Void post();
460
461 /*!
462 * ======== registerEvent ========
463 * Register an Event Object with a semaphore
464 *
465 * Ordinarily, an Event object and eventId are configured at
466 * Semaphore create time.
467 *
468 * This API is provided so that Semaphore-using middleware
469 * can support implicit Event posting without having to be
470 * retrofitted.
471 *
472 * After the Event object and eventId are registered with the
473 * Semaphore:
474
475 * Event_post(event, eventId) will be invoked when
476 * Semaphore_post(sem) is called.
477 *
478 * Event_pend(event, eventId, 0, timeout) will be invoked when
479 * Semaphore_pend(sem, timeout) is called.
480 *
481 * @param(event) Ptr to Event Object
482 * @param(eventId) Event ID
483 *
484 */
485 Void registerEvent(Event.Handle event, UInt eventId);
486
487 /*!
488 * ======== reset ========
489 * Reset semaphore count
490 *
491 * Resets the semaphore count to count.
492 * No task switch occurs when calling SEM_reset.
493 *
494 * @a(constraints)
495 * count must be greater than or equal to 0.
496 *
497 * No tasks should be waiting on the semaphore when
498 * Semaphore_reset is called.
499 *
500 * Semaphore_reset cannot be called by a Hwi or a Swi.
501 *
502 * @param(count) semaphore count
503 *
504 */
505 Void reset(Int count);
506
507 internal:
508
509 510 511 512
513 config Void (*eventPost)(Event.Handle, UInt);
514
515 config Void (*eventSync)(Event.Handle, UInt, UInt);
516
517 /*!
518 * ======== pendTimeout ========
519 * This function is the clock event handler for pend
520 */
521 Void pendTimeout(UArg arg);
522
523
524 enum PendState {
525 PendState_TIMEOUT = 0,
526 PendState_POSTED = 1,
527 PendState_CLOCK_WAIT = 2,
528 PendState_WAIT_FOREVER = 3
529 };
530
531
532 struct PendElem {
533 Task.PendElem tpElem;
534 PendState pendState;
535 };
536
537 struct Instance_State {
538 Event.Handle event;
539 UInt eventId;
540 Mode mode;
541 volatile UInt16 count;
542 Queue.Object pendQ;
543 };
544 }