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