1 2 3 4 5 6 7 8 9
10 11 12 13
14
15 package ti.sysbios.ipc;
16
17 import xdc.rov.ViewInfo;
18
19 import xdc.runtime.Diags;
20 import xdc.runtime.Log;
21 import xdc.runtime.Assert;
22
23 import ti.sysbios.misc.Queue;
24 import ti.sysbios.knl.Task;
25 import ti.sysbios.knl.Clock;
26
27 /*!
28 * ======== Semaphore ========
29 * Semaphore Manager.
30 *
31 * The Semaphore manager makes available a set of functions that manipulate
32 * semaphore objects. Semaphores can be used for task synchronization and
33 * mutual exclusion.
34 *
35 * Semaphores can be counting semaphores or binary semaphores. Counting
36 * semaphores keep track of the number of times the semaphore has been posted
37 * with post(). This is useful, for example, if you have a group of resources
38 * that are shared between tasks. Such tasks might call pend() to see if a
39 * resource is available before using one.
40 *
41 * Binary semaphores can have only two states: available (count = 1) and
42 * unavailable (count = 0). They can be used to share a single resource between
43 * tasks. They can also be used for a basic signaling mechanism, where the
44 * semaphore can be posted multiple times. Binary semaphores do not keep track
45 * of the count; they simply track whether the semaphore has been posted or not.
46 *
47 * The Mailbox module uses a counting semaphore internally to manage the
48 * count of free (or full) mailbox elements. Another example of a counting
49 * semaphore is an ISR that might fill multiple buffers of data for
50 * consumption by a task. After filling each buffer, the ISR puts the buffer on
51 * a queue and calls post(). The task waiting for the data calls pend(), which
52 * simply decrements the semaphore count and returns or blocks if the count is
53 * 0. The semaphore count thus tracks the number of full buffers available for
54 * the task.
55 *
56 * pend() is used to wait for a semaphore. The timeout parameter allows the
57 * task to wait until a timeout, wait indefinitely, or not wait at all. The
58 * return value is used to indicate if the semaphore was signaled successfully.
59 *
60 * post() is used to signal a semaphore. If a task is waiting for the
61 * semaphore, post() removes the task from the semaphore queue and puts it on
62 * the ready queue. If no tasks are waiting, post() simply increments the
63 * semaphore count and returns. For a binary semaphore the count is always
64 * set to one.
65 *
66 * @p(html)
67 * <h3> Calling Context </h3>
68 * <table border="1" cellpadding="3">
69 * <colgroup span="1"></colgroup> <colgroup span="5" align="center"></colgroup>
70 *
71 * <tr><th> Function </th><th> Hwi </th><th> Swi </th><th> Task </th><th> Main </th><th> Startup </th></tr>
72 * <!-- -->
73 * <tr><td> {@link #Params_init} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td></tr>
74 * <tr><td> {@link #construct} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
75 * <tr><td> {@link #create} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
76 * <tr><td> {@link #delete} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
77 * <tr><td> {@link #destruct} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
78 * <tr><td> {@link #getCount} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td></tr>
79 * <tr><td> {@link #pend} </td><td> N </td><td> N </td><td> Y </td><td> N </td><td> N </td></tr>
80 * <tr><td> {@link #post} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
81 * <tr><td> {@link #registerEvent} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> Y </td></tr>
82 * <tr><td colspan="6"> Definitions: <br />
83 * <ul>
84 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
85 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
86 * <li> <b>Task</b>: API is callable from a Task thread. </li>
87 * <li> <b>Main</b>: API is callable during any of these phases: </li>
88 * <ul>
89 * <li> In your module startup after this module is started (e.g. Semaphore_Module_startupDone() returns TRUE). </li>
90 * <li> During xdc.runtime.Startup.lastFxns. </li>
91 * <li> During main().</li>
92 * <li> During BIOS.startupFxns.</li>
93 * </ul>
94 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
95 * <ul>
96 * <li> During xdc.runtime.Startup.firstFxns.</li>
97 * <li> In your module startup before this module is started (e.g. Semaphore_Module_startupDone() returns FALSE).</li>
98 * </ul>
99 * </ul>
100 * </td></tr>
101 *
102 * </table>
103 * @p
104 */
105
106 @InstanceFinalize
107
108 module Semaphore
109 {
110 /*! Types of semaphores. */
111 enum Mode {
112 Mode_COUNTING, /*! Counting semaphore. */
113 Mode_BINARY /*! Binary Semaphore. */
114 };
115
116 metaonly struct BasicView {
117 String label;
118 String event;
119 String eventId;
120 String mode;
121 Int count;
122 String pendedTasks[];
123 };
124
125 @Facet
126 metaonly config ViewInfo.Instance rovViewInfo =
127 ViewInfo.create({
128 viewMap: [
129 ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}]
130 ]
131 });
132
133
134
135
136
137 /*! Logged on calls to Semaphore_post() */
138 config Log.Event LM_post = {
139 mask: Diags.USER1 | Diags.USER2,
140 msg: "LM_post: sem: 0x%x, count: %d"
141 };
142
143 /*! Logged on calls to Semaphore_pend() */
144 config Log.Event LM_pend = {
145 mask: Diags.USER1 | Diags.USER2,
146 msg: "LM_pend: sem: 0x%x, count: %d, timeout: %d"
147 };
148
149
150
151 /*!
152 * Generated by {@link #create} if {@link #supportsEvents} is false
153 * and an {@link ti.sysbios.ipc.Event} object is passed to
154 * {@link #create}.
155 */
156 config Assert.Id A_noEvents = {
157 msg: "A_noEvents: The Event.supportsEvents flag is disabled."
158 };
159
160 /*!
161 * Generated by {@link #pend} if BIOS_EVENT_ACQUIRED timeout is used
162 * with a Semaphore that has not been configured with an Event object
163 */
164 config Assert.Id A_invTimeout = {
165 msg: "A_invTimeout: Can't use BIOS_EVENT_ACQUIRED with this Semaphore."
166 };
167
168 /*!
169 * Asserted when {@link #pend} is called with non-zero timeout from other
170 * than a Task context.
171 */
172 config Assert.Id A_badContext = {
173 msg: "A_badContext: bad calling context. Must be called from a Task."
174 };
175
176 /*! Support Semaphores with Events? Default is false. */
177 config Bool supportsEvents = false;
178
179 instance:
180
181 /*!
182 * ======== create ========
183 * Create a Semaphore object.
184 *
185 * This function creates a new Semaphore object which is initialized to
186 * count.
187 *
188 * @param(count) initial semaphore count
189 */
190 create(Int count);
191
192 /*!
193 * ======== event ========
194 * event if using Events. Default is null.
195 *
196 * If event is non-null:
197 *
198 * Event_post(sem->event, sem->eventId) will be invoked when
199 * Semaphore_post() is called.
200 *
201 * Event_pend(sem->event, 0, sem->eventId, timeout) will be
202 * invoked when Semaphore_pend() is called.
203 */
204 config Event.Handle event = null;
205
206 /*!
207 * ======== eventId ========
208 * eventId if using Events. Default is 1.
209 */
210 config UInt eventId = 1;
211
212 /*!
213 * ======== mode ========
214 * Semaphore mode. Default is COUNTING.
215 *
216 * When mode is BINARY , the semaphore has only two states, available
217 * and unavailable. When mode is COUNTING, the semaphore keeps track of
218 * number of times a semaphore is posted.
219 */
220 config Mode mode = Mode_COUNTING;
221
222 /*!
223 * ======== getCount ========
224 * Get current semaphore count.
225 *
226 * This function returns the current value of the semaphore specified by
227 * the handle.
228 *
229 * @b(returns) current semaphore count
230 */
231 Int getCount();
232
233 /*!
234 * ======== pend ========
235 * Wait for a semaphore.
236 *
237 * If the semaphore count is greater than zero (available), this function
238 * decrements the count and returns TRUE. If the semaphore count is zero
239 * (unavailable), this function suspends execution of the current task
240 * until post() is called or the timeout expires.
241 *
242 * A timeout value of
243 * {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes
244 * the task to wait indefinitely for its semaphore to be posted.
245 *
246 * A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT}
247 * causes Semaphore_pend to return immediately.
248 *
249 * @param(timeout) return after this many system time units
250 *
251 * @b(returns) TRUE if successful, FALSE if timeout
252 */
253 Bool pend(UInt timeout);
254
255 /*!
256 * ======== post ========
257 * Signal a semaphore.
258 *
259 * Readies the first task waiting for the semaphore. If no task is
260 * waiting, This function simply increments the semaphore count and returns
261 * In case of binary semaphore the count has a maximum value of one.
262 */
263 Void post();
264
265 /*!
266 * ======== registerEvent ========
267 * Register an Event Object with a semaphore.
268 *
269 * Ordinarily, an Event object and eventId are configured at
270 * Semaphore create time.
271 *
272 * This API is provided so that Semaphore-using middleware
273 * can support implicit Event posting without having to be
274 * retrofitted.
275 *
276 * After the Event object and eventId are registered with the
277 * Semaphore:
278
279 * Event_post(event, eventId) will be invoked when
280 * Semaphore_post(sem) is called.
281 *
282 * Event_pend(event, eventId, 0, timeout) will be invoked when
283 * Semaphore_pend(sem, timeout) is called.
284 *
285 * @param(event) Ptr to Event Object
286 * @param(eventId) Event ID
287 *
288 */
289 Void registerEvent(Event.Handle event, UInt eventId);
290
291 /*!
292 * ======== reset ========
293 * @_nodoc
294 * Reset semaphore count.
295 *
296 * Resets the semaphore count to count.
297 *
298 * @param(count) semaphore count
299 *
300 */
301 Void reset(Int count);
302
303 internal:
304
305 306 307 308
309 config Void (*eventPost)(Event.Handle, UInt);
310
311 config Void (*eventSync)(Event.Handle, UInt, UInt);
312
313 /*!
314 * ======== pendTimeout ========
315 * This function is the clock event handler for pend
316 */
317 Void pendTimeout(UArg arg);
318
319
320 enum PendState {
321 PendState_TIMEOUT = 0,
322 PendState_POSTED = 1,
323 PendState_CLOCK_WAIT = 2,
324 PendState_WAIT_FOREVER = 3
325 };
326
327
328 struct PendElem {
329 Queue.Elem qElem;
330 Task.Handle task;
331 PendState pendState;
332 Clock.Handle clock;
333 };
334
335 struct Instance_State {
336 Event.Handle event;
337 UInt eventId;
338 Mode mode;
339 volatile UInt16 count;
340 Queue.Object pendQ;
341 };
342 }
343 344 345
346