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 package ti.sysbios.gates;
37
38 import xdc.rov.ViewInfo;
39 import xdc.runtime.Assert;
40 import ti.sysbios.knl.Queue;
41 import ti.sysbios.knl.Task;
42
43 /*!
44 * ======== GateMutexPri ========
45 * Mutex Gate with priority inheritance.
46 *
47 * GateMutexPri is a mutex gate (it can only be held by one thread at a time)
48 * which implements priority inheritance in order to prevent priority
49 * inversion. Priority inversion occurs when a high priority task has its
50 * priority effectively 'inverted' because it is waiting on a gate held by a
51 * low priority task.
52 *
53 * When multiple tasks wait on this gate, they will receive the gate in order
54 * of priority (higher priority tasks will receive the gate first). This is
55 * because the queue of tasks waiting on a GateMutexPri is sorted by priority,
56 * not FIFO.
57 *
58 * @p(html)
59 * <h3> Problem: Priority Inversion </h3>
60 * The following example demonstrates priority inversion.
61 * A system has three tasks, Low, Med, and High, each with the priority
62 * suggested by its name. Task Low runs first and acquires the gate. Task High
63 * is scheduled and preempts Low. Task High tries to acquire the gate, and
64 * waits on it. Next, task Med is scheduled and preempts task Low. Now task
65 * High must wait for both task Med and task Low to finish before it can
66 * continue. In this situation, task Low has in effect lowered task High's
67 * priority to that of Low.
68 *
69 * <h3> Solution: Priority Inheritance </h3>
70 * To guard against priority inversion, GateMutexPri implements priority
71 * inheritance: when task High tries to acquire a gate that is owned by task
72 * Low, task Low's priority will be temporarily raised to that of High, as
73 * long as High is waiting on the gate. Task High will "donate" its priority
74 * to task Low.
75 *
76 * When multiple tasks wait on the gate, the gate owner will receive the
77 * highest priority of any of the tasks waiting on the gate.
78 *
79 * <h3> Caveats </h3>
80 * Priority inheritance is not a complete guard against priority inversion.
81 * Tasks only donate priority on the call to gate, so if a task has its
82 * priority raised while waiting on a gate, that priority will not carry
83 * through to the gate owner.
84 * This can occur in situations involving multiple gates. A system has four
85 * tasks: VeryLow, Low, Med, and High, each with the priority suggested by its
86 * name. Task VeryLow runs first and acquires gate A. Task Low runs next and
87 * acquires gate B, then waits on gate A. Task High runs and waits on gate B.
88 * Task High has donated its priority to task Low, but Low is blocked on
89 * VeryLow, so priority inversion occurs despite the use of the gate.
90 * The solution to this problem is to design around it. If gate A may be
91 * needed by a high-priority, time-critical task, then it should be a design
92 * rule that no task holds this gate for a long time, or blocks while holding
93 * this gate.
94 *
95 * <h3> Miscellaneous </h3>
96 * Calls to enter() may block, so this gate can only be used in the task
97 * context.
98 *
99 * GateMutexPri is non-deterministic on calls to gate because it keeps the
100 * queue of waiting tasks sorted by priority.
101 *
102 * @p(html)
103 * <h3> Calling Context </h3>
104 * <table border="1" cellpadding="3">
105 * <colgroup span="1"></colgroup> <colgroup span="5" align="center">
106 * </colgroup>
107 *
108 * <tr><th> Function </th><th> Hwi </th><th> Swi </th><th> Task </th>
109 * <th> Main </th><th> Startup </th></tr>
110 * <!-- -->
111 * <tr><td> {@link #Params_init} </td><td> Y </td><td> Y </td>
112 * <td> Y </td><td> Y </td><td> Y </td></tr>
113 * <tr><td> {@link #query} </td><td> Y </td><td> Y </td>
114 * <td> Y </td><td> Y </td><td> Y </td></tr>
115 * <tr><td> {@link #construct} </td><td> Y </td><td> Y </td>
116 * <td> Y </td><td> Y </td><td> N </td></tr>
117 * <tr><td> {@link #create} </td><td> N* </td><td> N* </td>
118 * <td> Y </td><td> Y </td><td> N </td></tr>
119 * <tr><td> {@link #delete} </td><td> N* </td><td> N* </td>
120 * <td> Y </td><td> Y </td><td> N </td></tr>
121 * <tr><td> {@link #destruct} </td><td> Y </td><td> Y </td>
122 * <td> Y </td><td> Y </td><td> N </td></tr>
123 * <tr><td> {@link #enter} </td><td> N </td><td> N </td>
124 * <td> Y </td><td> Y** </td><td> N </td></tr>
125 * <tr><td> {@link #leave} </td><td> N </td><td> N </td>
126 * <td> Y </td><td> Y** </td><td> N </td></tr>
127 * <tr><td colspan="6"> Definitions: <br />
128 * <ul>
129 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
130 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
131 * <li> <b>Task</b>: API is callable from a Task thread. </li>
132 * <li> <b>Main</b>: API is callable during any of these phases: </li>
133 * <ul>
134 * <li> In your module startup after this module is started
135 * (e.g. GateMutexPri_Module_startupDone() returns TRUE). </li>
136 * <li> During xdc.runtime.Startup.lastFxns. </li>
137 * <li> During main().</li>
138 * <li> During BIOS.startupFxns.</li>
139 * </ul>
140 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
141 * <ul>
142 * <li> During xdc.runtime.Startup.firstFxns.</li>
143 * <li> In your module startup before this module is started
144 * (e.g. GateMutexPri_Module_startupDone() returns FALSE).</li>
145 * </ul>
146 * <li> <b>*</b>: Assuming blocking Heap is used for creation. </li>
147 * <li> <b>**</b>: Must be used in enter/leave pairs. </li>
148 * </ul>
149 * </td></tr>
150 *
151 * </table>
152 * @p
153 */
154
155 @InstanceFinalize
156
157 module GateMutexPri inherits xdc.runtime.IGateProvider
158 {
159
160 /*!
161 * ======== BasicView ========
162 * @_nodoc
163 */
164 metaonly struct BasicView {
165 String status;
166 String label;
167 UInt mutexCnt;
168 String owner;
169 Int ownerOrigPri;
170 Int ownerCurrPri;
171 }
172
173 /*!
174 * ======== DetailedView ========
175 * @_nodoc
176 */
177 metaonly struct DetailedView {
178 String status;
179 String label;
180 UInt mutexCnt;
181 String owner;
182 Int ownerOrigPri;
183 Int ownerCurrPri;
184 String pendedTasks[];
185 }
186
187 /*!
188 * ======== rovViewInfo ========
189 * @_nodoc
190 */
191 @Facet
192 metaonly config ViewInfo.Instance rovViewInfo =
193 ViewInfo.create({
194 viewMap: [
195 ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}],
196 ['Detailed', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitDetailed', structName: 'DetailedView'}],
197 ]
198 });
199
200 /*!
201 * Assert when GateMutexPri_enter() is not called from correct context.
202 * GateMutexPri_enter() can only be called from main() or Task context (not
203 * Hwi or Swi).
204 *
205 * Common causes and workarounds for hitting this Assert:
206 *
207 * - Calling printf() from a Hwi or Swi thread.
208 * @p(blist)
209 * - Use xdc.runtime.System_printf (with SysMin) instead.
210 * @p
211 * - Calling System_printf() from a Hwi or Swi thread when using SysStd.
212 * @p(blist)
213 * - Use xdc.runtime.SysMin instead of xdc.runtume.SysStd.
214 * - Use a different type of Gate for
215 * {@link ti.sysbios.BIOS#rtsGateType BIOS.rtsGateType}
216 * (ie {@link ti.sysbios.BIOS#GateHwi BIOS.GateHwi}
217 * or {@link ti.sysbios.BIOS#GateSwi BIOS.GateSwi})
218 * @p
219 * - Calling Memory_alloc() from a Hwi or Swi thread.
220 * @p(blist)
221 * - Use a different Heap manager
222 * @p
223 */
224 config Assert.Id A_badContext = {
225 msg: "A_badContext: bad calling context. See GateMutexPri API doc for details."
226 };
227
228 /*!
229 * ======== A_enterTaskDisabled ========
230 * Asserted in GateMutexPri_enter()
231 *
232 * Assert raised if GateMutexPri_enter() is called with the Task or
233 * Swi scheduler disabled.
234 */
235 config Assert.Id A_enterTaskDisabled = {
236 msg: "A_enterTaskDisabled: Cannot call GateMutexPri_enter() while the Task or Swi scheduler is disabled."
237 };
238
239 instance:
240
241 override IArg enter();
242
243 override Void leave(IArg key);
244
245 internal:
246
247 Void insertPri(ti.sysbios.knl.Queue.Object *queue,
248 ti.sysbios.knl.Queue.Elem *newElem,
249 Int newPri);
250
251
252 struct Instance_State {
253 volatile UInt mutexCnt;
254 volatile Int ownerOrigPri;
255 volatile Task.Handle owner;
256 Queue.Object pendQ;
257 };
258 }