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