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