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