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 @InstanceFinalize
152 @InstanceInitStatic
153
154 module Semaphore
155 {
156 /*!
157 * Semaphore types.
158 *
159 * These enumerations specify the type of semaphore.
160 *
161 * Tasks wait for the semaphore in FIFO order unless the PRIORITY
162 * option is chosen.
163 *
164 * For PRIORITY semaphores, the pending task will be
165 * inserted in the waiting list before the first task that has
166 * lower priority. This ensures that tasks of equal priority will
167 * pend in FIFO order.
168 *
169 * @a(WARNING)
170 * PRIORITY semaphores have a potential to increase the interrupt
171 * latency in the system since interrupts are disabled while the list of
172 * tasks waiting on the semaphore is scanned for the proper insertion
173 * point. This is typically about a dozen instructions per waiting task.
174 * For example, if you have 10 tasks of higher priority waiting, then all
175 * 10 will be checked with interrupts disabled before the new task is
176 * entered onto the list.
177 */
178 enum Mode {
179 Mode_COUNTING = 0x0, /*! Counting (FIFO) */
180 Mode_BINARY = 0x1, /*! Binary (FIFO) */
181 Mode_COUNTING_PRIORITY = 0x2, /*! Counting (priority-based) */
182 Mode_BINARY_PRIORITY = 0x3 /*! Binary (priority-based) */
183 };
184
185 /*!
186 * ======== BasicView ========
187 * @_nodoc
188 */
189 metaonly struct BasicView {
190 String label;
191 String event;
192 String eventId;
193 String mode;
194 Int count;
195 String pendedTasks[];
196 };
197
198 /*!
199 * ======== rovViewInfo ========
200 * @_nodoc
201 */
202 @Facet
203 metaonly config ViewInfo.Instance rovViewInfo =
204 ViewInfo.create({
205 viewMap: [
206 ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}]
207 ]
208 });
209
210
211
212 /*!
213 * ======== LM_post ========
214 * Logged on calls to Semaphore_post()
215 */
216 config Log.Event LM_post = {
217 mask: Diags.USER1 | Diags.USER2,
218 msg: "LM_post: sem: 0x%x, count: %d"
219 };
220
221 /*!
222 * ======== LM_pend ========
223 * Logged on calls to Semaphore_pend()
224 */
225 config Log.Event LM_pend = {
226 mask: Diags.USER1 | Diags.USER2,
227 msg: "LM_pend: sem: 0x%x, count: %d, timeout: %d"
228 };
229
230 /*!
231 * ======== A_noEvents ========
232 * Assert raised if application uses Event but it's not supported
233 *
234 * This assertion is triggered by {@link #create} if
235 * {@link #supportsEvents} is false and an {@link ti.sysbios.knl.Event}
236 * object is passed to {@link #create}.
237 */
238 config Assert.Id A_noEvents = {
239 msg: "A_noEvents: The Event.supportsEvents flag is disabled."
240 };
241
242 /*!
243 * ======== A_invTimeout ========
244 * @_nodoc
245 * This assertion is no longer used
246 */
247 config Assert.Id A_invTimeout = {
248 msg: "A_invTimeout: Can't use BIOS_EVENT_ACQUIRED with this Semaphore."
249 };
250
251 /*!
252 * ======== A_badContext ========
253 * Assert raised if an operation is invalid in the current calling context
254 *
255 * Asserted when {@link #pend} is called with non-zero timeout from
256 * other than a Task context.
257 */
258 config Assert.Id A_badContext = {
259 msg: "A_badContext: bad calling context. Must be called from a Task."
260 };
261
262 /*!
263 * ======== A_overflow ========
264 * Assert raised if the semaphore count is incremented past 65535
265 *
266 * Asserted when Semaphore_post() has been called when the 16 bit
267 * semaphore count is at its maximum value of 65535.
268 */
269 config Assert.Id A_overflow = {
270 msg: "A_overflow: Count has exceeded 65535 and rolled over."
271 };
272
273 /*!
274 * ======== A_pendTaskDisabled ========
275 * Asserted in Sempahore_pend()
276 *
277 * Assert raised if Semaphore_pend() is called with the Task or
278 * Swi scheduler disabled.
279 */
280 config Assert.Id A_pendTaskDisabled = {
281 msg: "A_pendTaskDisabled: Cannot call Semaphore_pend() while the Task or Swi scheduler is disabled."
282 };
283
284
285
286 /*!
287 * Error raised when BIOS.mpeEnabled is TRUE and Semaphore object passed to
288 * Semaphore_construct() is not in Kernel address space. This can happen if
289 * a user Task passes a Semaphore object that resides in unprivileged
290 * memory to Semaphore_construct().
291 */
292 config Error.Id E_objectNotInKernelSpace = {
293 msg: "E_objectNotInKernelSpace: Semaphore object passed not in Kernel address space."
294 };
295
296 /*!
297 * ======== supportsEvents ========
298 * Support Semaphores with Events?
299 *
300 * The default for this parameter is false.
301 */
302 config Bool supportsEvents = false;
303
304 /*!
305 * ======== supportsPriority ========
306 * Support Task priority pend queuing?
307 *
308 * The default for this parameter is true.
309 */
310 config Bool supportsPriority = true;
311
312 /*!
313 * ======== testStaticInlines ========
314 * @_nodoc
315 * Used for code coverage testing.
316 */
317 Void testStaticInlines();
318
319 instance:
320
321 /*!
322 * ======== create ========
323 * Create a Semaphore object
324 *
325 * This function creates a new Semaphore object which is initialized to
326 * count.
327 *
328 * @param(count) initial semaphore count
329 *
330 * @a(NOTE)
331 * The "count" argument should not be a negative number as the Semaphore
332 * count is stored as a 16-bit unsigned integer inside the Semaphore
333 * object.
334 */
335 create(Int count);
336
337 /*!
338 * ======== event ========
339 * Event instance to use if non-NULL
340 *
341 * The default value of this parameter is null. If event is non-null:
342 * @p(blist)
343 * - Event_post(sem->event, sem->eventId) will be invoked when
344 * Semaphore_post() is called.
345 *
346 * - Event_pend(sem->event, 0, sem->eventId, timeout) will be
347 * invoked when Semaphore_pend() is called.
348 * @p
349 */
350 config Event.Handle event = null;
351
352 /*!
353 * ======== eventId ========
354 * eventId if using Events
355 *
356 * The default for this parameters is 1.
357 */
358 config UInt eventId = 1;
359
360 /*!
361 * ======== mode ========
362 * Semaphore mode
363 *
364 * When mode is BINARY, the semaphore has only two states, available
365 * and unavailable. When mode is COUNTING, the semaphore keeps track of
366 * number of times a semaphore is posted.
367 *
368 * The default for this parameter is COUNTING.
369 */
370 config Mode mode = Mode_COUNTING;
371
372 /*!
373 * ======== getCount ========
374 * Get current semaphore count
375 *
376 * This function returns the current value of the semaphore specified by
377 * the handle.
378 *
379 * A semaphore's count is incremented when Semaphore_post() is called.
380 * If configured as a binary semaphore, the count will not increment past
381 * 1. If configured as a counting semaphore, the count will continue
382 * incrementing and will rollover to zero after reaching a count of
383 * 65,535. Care must be taken in applications to avoid the rollover
384 * situation as a count of zero will always be interpreted as an empty
385 * semaphore.
386 *
387 * A semaphore's count is decremented, if non-zero, when Semaphore_pend()
388 * is called. A task will block on a semaphore if the count is zero when
389 * Semaphore_pend() is called. An empty semaphore will always have a
390 * count of zero regardless of the number of tasks that are blocked on
391 * it.
392 *
393 * @b(returns) current semaphore count
394 */
395 Int getCount();
396
397 /*!
398 * ======== pend ========
399 * Wait for a semaphore
400 *
401 * If the semaphore count is greater than zero (available), this function
402 * decrements the count and returns TRUE. If the semaphore count is zero
403 * (unavailable), this function suspends execution of the current task
404 * (leaving the count equal to zero) until post() is called or the
405 * timeout expires.
406 *
407 * A timeout value of
408 * {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER} causes
409 * the task to wait indefinitely for its semaphore to be posted.
410 *
411 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT BIOS_NO_WAIT}
412 * causes Semaphore_pend to return immediately.
413 *
414 * @a(Event Object Note)
415 * If the Semaphore object has been configured with an embedded Event
416 * object, then prior to returning from this function, the Event object's
417 * state is updated to reflect the new value of 'count'.
418 * If 'count' is zero, then the configured Event_Id is cleared in the
419 * Event object. If 'count' is non-zero, then the configured Event_Id
420 * is set in the Event object.
421 *
422 * @param(timeout) return after this many system time units
423 *
424 * @b(returns) TRUE if successful, FALSE if timeout
425 */
426 Bool pend(UInt32 timeout);
427
428 /*!
429 * ======== post ========
430 * Signal a semaphore.
431 *
432 * If any tasks are waiting on the semaphore, this function readies
433 * the first task waiting for the semaphore without incrementing
434 * the count. If no task is waiting, this function simply increments
435 * the semaphore count and returns. In the case of a binary semaphore,
436 * the count has a maximum value of one.
437 */
438 Void post();
439
440 /*!
441 * ======== registerEvent ========
442 * Register an Event Object with a semaphore
443 *
444 * Ordinarily, an Event object and eventId are configured at
445 * Semaphore create time.
446 *
447 * This API is provided so that Semaphore-using middleware
448 * can support implicit Event posting without having to be
449 * retrofitted.
450 *
451 * After the Event object and eventId are registered with the
452 * Semaphore:
453
454 * Event_post(event, eventId) will be invoked when
455 * Semaphore_post(sem) is called.
456 *
457 * Event_pend(event, eventId, 0, timeout) will be invoked when
458 * Semaphore_pend(sem, timeout) is called.
459 *
460 * @param(event) Ptr to Event Object
461 * @param(eventId) Event ID
462 *
463 */
464 Void registerEvent(Event.Handle event, UInt eventId);
465
466 /*!
467 * ======== reset ========
468 * Reset semaphore count
469 *
470 * Resets the semaphore count to count.
471 * No task switch occurs when calling SEM_reset.
472 *
473 * @a(constraints)
474 * count must be greater than or equal to 0.
475 *
476 * No tasks should be waiting on the semaphore when
477 * Semaphore_reset is called.
478 *
479 * Semaphore_reset cannot be called by a Hwi or a Swi.
480 *
481 * @param(count) semaphore count
482 *
483 */
484 Void reset(Int count);
485
486 internal:
487
488 489 490 491
492 config Void (*eventPost)(Event.Handle, UInt);
493
494 config Void (*eventSync)(Event.Handle, UInt, UInt);
495
496 /*!
497 * ======== pendTimeout ========
498 * This function is the clock event handler for pend
499 */
500 Void pendTimeout(UArg arg);
501
502
503 enum PendState {
504 PendState_TIMEOUT = 0,
505 PendState_POSTED = 1,
506 PendState_CLOCK_WAIT = 2,
507 PendState_WAIT_FOREVER = 3
508 };
509
510
511 struct PendElem {
512 Task.PendElem tpElem;
513 PendState pendState;
514 };
515
516 struct Instance_State {
517 Event.Handle event;
518 UInt eventId;
519 Mode mode;
520 volatile UInt16 count;
521 Queue.Object pendQ;
522 };
523 }