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