|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\include\nkernsmp\dfcs.h |
|
15 // |
|
16 // WARNING: This file contains some APIs which are internal and are subject |
|
17 // to change without notice. Such APIs should therefore not be used |
|
18 // outside the Kernel and Hardware Services package. |
|
19 // |
|
20 |
|
21 #ifndef __DFCS_H__ |
|
22 #define __DFCS_H__ |
|
23 |
|
24 #include <nklib.h> |
|
25 #include <nk_event.h> |
|
26 |
|
27 class NTimer; |
|
28 class NThreadBase; |
|
29 class NThread; |
|
30 class NFastSemaphore; |
|
31 class NFastMutex; |
|
32 class TSubScheduler; |
|
33 class TCancelIPI; |
|
34 |
|
35 /******************************************** |
|
36 * Delayed function call queue |
|
37 ********************************************/ |
|
38 |
|
39 /** |
|
40 @publishedPartner |
|
41 @released |
|
42 |
|
43 The number of DFC priorities the system has, which range from 0 |
|
44 to KNumDfcPriorities - 1. |
|
45 */ |
|
46 const TInt KNumDfcPriorities=8; |
|
47 |
|
48 /** |
|
49 @publishedPartner |
|
50 @released |
|
51 |
|
52 The highest priority level for a DFC, which is equal to KNumDfcPriorities + 1. |
|
53 */ |
|
54 const TInt KMaxDfcPriority=KNumDfcPriorities-1; |
|
55 |
|
56 class TDfc; |
|
57 /** |
|
58 @publishedPartner |
|
59 @prototype |
|
60 |
|
61 Defines a DFC queue. |
|
62 |
|
63 Each DFC queue is associated with a thread. |
|
64 |
|
65 @see TDfc |
|
66 */ |
|
67 class TDfcQue : public TPriList<TDfc,KNumDfcPriorities> |
|
68 { |
|
69 public: |
|
70 IMPORT_C TDfcQue(); |
|
71 |
|
72 inline TBool IsEmpty(); /**< @internalComponent */ |
|
73 static void ThreadFunction(TAny* aDfcQ); |
|
74 public: |
|
75 NThreadBase* iThread; /**< @internalComponent */ |
|
76 }; |
|
77 |
|
78 /** |
|
79 @internalComponent |
|
80 */ |
|
81 inline TBool TDfcQue::IsEmpty() |
|
82 { return (iPresent[0]==0); } |
|
83 |
|
84 /******************************************** |
|
85 * Delayed function call |
|
86 ********************************************/ |
|
87 |
|
88 /** |
|
89 @publishedPartner |
|
90 @released |
|
91 |
|
92 The function type that can be set to run as a DFC or IDFC. |
|
93 |
|
94 @see TDfc |
|
95 */ |
|
96 typedef NEventFn TDfcFn; |
|
97 |
|
98 /** |
|
99 @publishedPartner |
|
100 @prototype |
|
101 |
|
102 Defines a Deferred Function Call (DFC) or Immediate Deferred Function Call (IDFC). |
|
103 |
|
104 A DFC is a kernel object that specifies a function to be run in a thread, |
|
105 which is processing a DFC queue. A DFC is added to a DFC queue that is |
|
106 associated with a given thread, where it is cooperatively scheduled with other |
|
107 DFCs on that queue. Queued DFCs are run in order of their priority, followed |
|
108 by the order they where queued. When the DFC gets to run, the function is run |
|
109 kernel side, and no other DFC in this queue will get to run until it |
|
110 completes. A DFC can be queued from any context. |
|
111 |
|
112 An IDFC is run as soon as the scheduler is next run, which is during the IRQ |
|
113 postamble if queued from an ISR; when the currently-running IDFC completes if |
|
114 queued from an IDFC; or when the kernel is next unlocked if queued from thread |
|
115 context. Unlike a DFC, the IDFC is not run from a thread context, and its |
|
116 execution time must be much smaller. For these reasons, IDFCs are rarely used |
|
117 directly, but are used for implementation of the kernel and RTOS personality |
|
118 layers. An important use of IDFCs is in the implementation of queuing DFCs from |
|
119 an ISR context. IDFCs are run with interrupts enabled but the kernel locked. |
|
120 */ |
|
121 class TDfc : public NEventHandler |
|
122 { |
|
123 // iPriority<KNumDfcPriorities => DFC, otherwise IDFC |
|
124 // |
|
125 // iHState2 = 0 normally |
|
126 // = Bit n is set if CPU n is waiting to cancel this DFC |
|
127 // iHState1 = 0 if not on any list |
|
128 // = 100nnnnn if on CPU n endogenous IDFC/DFC queue |
|
129 // = 101nnnnn if on CPU n exogenous IDFC queue |
|
130 // = 110nnnnn if running on CPU n |
|
131 // = 111nnnnn if running on CPU n and a second execution is also pending (Add() was called while running) |
|
132 // = 011nnnnn if running on CPU n and a second idle queue is also pending (QueueOnIdle() was called while running) |
|
133 // = 0010000g if idle DFC generation g (could be either on idle queue or CPU endogenous IDFC/DFC queue) |
|
134 // = 00000001 if on final DFC queue |
|
135 // iHState1 and iHState2 are accessed together as a single 16 bit iDfcState |
|
136 // |
|
137 // iHState0 is set to 0 when a DFC/IDFC is added to a CPUs endogenous IDFC |
|
138 // queue or to the idle queue. It is set to 1 if and when BeginTiedEvent() |
|
139 // is subsequently called (thus only for tied IDFCs). |
|
140 // |
|
141 // For IDFC iHType = EEventHandlerIDFC |
|
142 // For DFC iHType = priority (0 to 7) and iTied points to TDfcQue (since DFCs can't be tied) |
|
143 // |
|
144 public: |
|
145 IMPORT_C TDfc(TDfcFn aFunction, TAny* aPtr); // create IDFC |
|
146 IMPORT_C TDfc(NSchedulable* aTied, TDfcFn aFunction, TAny* aPtr); // create IDFC tied to a thread or group |
|
147 IMPORT_C TDfc(TDfcFn aFunction, TAny* aPtr, TInt aPriority); // create DFC, queue to be set later |
|
148 IMPORT_C TDfc(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority); // create DFC |
|
149 IMPORT_C ~TDfc(); |
|
150 IMPORT_C TBool Add(); // call from ISR or IDFC or thread with kernel locked |
|
151 IMPORT_C TBool Cancel(); // call from anywhere except ISR |
|
152 IMPORT_C TBool Enque(); // call from thread |
|
153 IMPORT_C TBool Enque(NFastMutex* aMutex); // call from thread, signal fast mutex (anti-thrash) |
|
154 IMPORT_C TBool DoEnque(); // call from IDFC or thread with kernel locked |
|
155 IMPORT_C TBool RawAdd(); // same as Add() but without checks for 'correct' usage or other instrumentation |
|
156 IMPORT_C TBool QueueOnIdle(); // queue the DFC to be run when the system goes idle |
|
157 IMPORT_C TInt SetTied(NSchedulable* aTied); // tie an IDFC to a thread or group |
|
158 IMPORT_C NThreadBase* Thread(); // thread on which DFC runs, NULL for IDFC |
|
159 public: |
|
160 inline TBool Queued(); |
|
161 inline TBool IsIDFC(); |
|
162 inline TBool IsDFC(); |
|
163 inline void SetDfcQ(TDfcQue* aDfcQ); |
|
164 inline void SetFunction(TDfcFn aDfcFn); |
|
165 inline void SetPriority(TInt aPriority); /**< @internalComponent */ |
|
166 private: |
|
167 inline TBool IsValid(); /**< @internalComponent */ |
|
168 private: |
|
169 TUint32 AddStateChange(); /**< @internalComponent */ |
|
170 TUint32 MoveToFinalQStateChange(); /**< @internalComponent */ |
|
171 TUint32 TransferIDFCStateChange(TInt aCpu); /**< @internalComponent */ |
|
172 TUint32 RunIDFCStateChange(); /**< @internalComponent */ |
|
173 TUint32 EndIDFCStateChange(TSubScheduler*); /**< @internalComponent */ |
|
174 TUint32 EndIDFCStateChange2(); /**< @internalComponent */ |
|
175 TUint32 CancelInitialStateChange(); /**< @internalComponent */ |
|
176 TUint32 CancelFinalStateChange(); /**< @internalComponent */ |
|
177 TUint32 QueueOnIdleStateChange(); /**< @internalComponent */ |
|
178 void ResetState(); /**< @internalComponent */ |
|
179 |
|
180 friend class TSubScheduler; |
|
181 friend class TCancelIPI; |
|
182 friend class TDfcQue; |
|
183 friend class NTimer; |
|
184 }; |
|
185 |
|
186 /** |
|
187 @publishedPartner |
|
188 @prototype |
|
189 |
|
190 Used to find out if the DFC/IDFC is queued on either the pending or final DFC queue. |
|
191 |
|
192 @return TRUE if the DFC/IDFC is queued, otherwise FALSE. |
|
193 |
|
194 */ |
|
195 inline TBool TDfc::Queued() |
|
196 { TUint32 state = i8816.iHState16; return state && (state&0xE0)!=0xC0; } |
|
197 |
|
198 /** |
|
199 @publishedPartner |
|
200 @prototype |
|
201 |
|
202 Determines if the object represents an IDFC rather than a DFC. |
|
203 |
|
204 @return TRUE if this represents an IDFC, otherwise FALSE. |
|
205 */ |
|
206 inline TBool TDfc::IsIDFC() |
|
207 { return iHType == EEventHandlerIDFC; } |
|
208 |
|
209 /** |
|
210 @publishedPartner |
|
211 @prototype |
|
212 |
|
213 Determines if the object represents a DFC rather than an IDFC. |
|
214 |
|
215 @return TRUE if this represents a DFC, otherwise FALSE. |
|
216 */ |
|
217 inline TBool TDfc::IsDFC() |
|
218 { return iHType < KNumDfcPriorities; } |
|
219 |
|
220 |
|
221 /** |
|
222 @publishedPartner |
|
223 @prototype |
|
224 |
|
225 Sets the DFC queue that the DFC is to added to and executed by. |
|
226 |
|
227 Note that this function should only be used in the initialisation of the DFC, |
|
228 when it is not on any queue. This function does not move the DFC from one |
|
229 queue to another. |
|
230 |
|
231 @param aDfcQ |
|
232 |
|
233 The DFC queue that the DFC is to be added to and executed by. |
|
234 |
|
235 */ |
|
236 inline void TDfc::SetDfcQ(TDfcQue* aDfcQ) |
|
237 { iDfcQ = aDfcQ; } |
|
238 |
|
239 /** |
|
240 @publishedPartner |
|
241 @prototype |
|
242 |
|
243 Sets the function that is run when the DFC/IDFC is scheduled. |
|
244 |
|
245 @param aDfcFn |
|
246 |
|
247 The function that the DFC/IDFC runs when it is scheduled. |
|
248 |
|
249 */ |
|
250 inline void TDfc::SetFunction(TDfcFn aDfcFn) |
|
251 { iFn = aDfcFn; } |
|
252 |
|
253 /** |
|
254 @internalComponent |
|
255 */ |
|
256 inline void TDfc::SetPriority(TInt aPriority) |
|
257 { iHState = (TUint8)aPriority; } |
|
258 |
|
259 #ifdef __INCLUDE_TDFC_DEFINES__ |
|
260 /** |
|
261 @internalComponent |
|
262 */ |
|
263 #define iDfcState (i8816.iHState16) |
|
264 |
|
265 /** |
|
266 @internalComponent |
|
267 */ |
|
268 #define DFC_STATE(p) ((p)->i8816.iHState16) |
|
269 #endif |
|
270 |
|
271 |
|
272 /******************************************** |
|
273 * Kernel-side asynchronous request, |
|
274 * based on DFC queueing |
|
275 ********************************************/ |
|
276 |
|
277 /** |
|
278 @internalComponent |
|
279 */ |
|
280 class TAsyncRequest : protected TDfc |
|
281 { |
|
282 public: |
|
283 IMPORT_C void Send(TDfc* aCompletionDfc); |
|
284 IMPORT_C void Send(NFastSemaphore* aCompletionSemaphore); |
|
285 IMPORT_C TInt SendReceive(); |
|
286 IMPORT_C void Cancel(); |
|
287 IMPORT_C void Complete(TInt aResult); |
|
288 inline TBool PollForCancel() |
|
289 { return iCancel; } |
|
290 protected: |
|
291 IMPORT_C TAsyncRequest(TDfcFn aFunction, TDfcQue* aDfcQ, TInt aPriority); |
|
292 protected: |
|
293 TAny* iCompletionObject; |
|
294 volatile TBool iCancel; |
|
295 TInt iResult; |
|
296 }; |
|
297 |
|
298 |
|
299 #endif |