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