45 { |
45 { |
46 iPriority = 0; |
46 iPriority = 0; |
47 iReady = 0; |
47 iReady = 0; |
48 iCurrent = 0; |
48 iCurrent = 0; |
49 iLastCpu = 0; |
49 iLastCpu = 0; |
50 iNSchedulableSpare1 = 0; |
|
51 iPauseCount = 0; |
50 iPauseCount = 0; |
52 iSuspended = 0; |
51 iSuspended = 0; |
53 iNSchedulableSpare2 = 0; |
52 iACount = 0; |
|
53 iPreferredCpu = 0; |
|
54 iActiveState = 0; |
|
55 i_NSchedulable_Spare2 = 0; |
|
56 iTransientCpu = 0; |
|
57 iForcedCpu = 0; |
|
58 iLbState = ELbState_Inactive; |
54 iCpuChange = 0; |
59 iCpuChange = 0; |
55 iStopping = 0; |
60 iStopping = 0; |
56 iFreezeCpu = 0; |
61 iFreezeCpu = 0; |
57 iParent = (NSchedulable*)0xdeadbeef; |
62 iParent = (NSchedulable*)0xdeadbeef; |
58 iCpuAffinity = 0; |
63 iCpuAffinity = 0; |
59 new (i_IDfcMem) TDfc(&DeferredReadyIDfcFn, this); |
64 new (i_IDfcMem) TDfc(&DeferredReadyIDfcFn, this); |
60 iEventState = 0; |
65 iEventState = 0; |
61 iTotalCpuTime64 = 0; |
66 iRunCount.i64 = 0; |
62 } |
67 iLastRunTime.i64 = 0; |
|
68 iTotalCpuTime.i64 = 0; |
|
69 iLastActivationTime.i64 = 0; |
|
70 iTotalActiveTime.i64 = 0; |
|
71 iSavedCpuTime.i64 = 0; |
|
72 iSavedActiveTime.i64 = 0; |
|
73 iLbLink.iNext = 0; |
|
74 memclr(&iLbInfo, EMaxLbInfoSize); |
|
75 } |
|
76 |
|
77 void NSchedulable::AddToEnumerateList() |
|
78 { |
|
79 TScheduler& s = TheScheduler; |
|
80 SIterDQ& dq = iParent ? s.iAllThreads : s.iAllGroups; |
|
81 NKern::Lock(); |
|
82 s.iEnumerateLock.LockOnly(); |
|
83 dq.Add(&iEnumerateLink); |
|
84 TUint32 active = s.iThreadAcceptCpus; |
|
85 TUint32 cpus = active & iCpuAffinity; |
|
86 if (!cpus) |
|
87 cpus = active; // can't run on any currently active CPU, just pick an active one until it becomes ready |
|
88 TInt ecpu = __e32_find_ls1_32(cpus); |
|
89 iEventState = (ecpu<<EEventCpuShift) | (ecpu<<EThreadCpuShift); |
|
90 s.iEnumerateLock.UnlockOnly(); |
|
91 NKern::Unlock(); |
|
92 } |
|
93 |
63 |
94 |
64 /****************************************************************************** |
95 /****************************************************************************** |
65 * NThreadGroup |
96 * NThreadGroup |
66 ******************************************************************************/ |
97 ******************************************************************************/ |
67 NThreadGroup::NThreadGroup() |
98 NThreadGroup::NThreadGroup() |
68 { |
99 { |
|
100 iACount = 1; |
69 iParent = 0; |
101 iParent = 0; |
70 iThreadCount = 0; |
102 iThreadCount = 0; |
71 new (&iSSpinLock) TSpinLock(TSpinLock::EOrderThreadGroup); |
103 new (&iSSpinLock) TSpinLock(TSpinLock::EOrderThreadGroup); |
72 } |
104 } |
73 |
105 |
77 @prototype |
109 @prototype |
78 */ |
110 */ |
79 EXPORT_C TInt NKern::GroupCreate(NThreadGroup* aGroup, SNThreadGroupCreateInfo& aInfo) |
111 EXPORT_C TInt NKern::GroupCreate(NThreadGroup* aGroup, SNThreadGroupCreateInfo& aInfo) |
80 { |
112 { |
81 new (aGroup) NThreadGroup(); |
113 new (aGroup) NThreadGroup(); |
82 aGroup->iCpuAffinity = aInfo.iCpuAffinity; |
114 aGroup->iDestructionDfc = aInfo.iDestructionDfc; |
|
115 aGroup->iCpuAffinity = NSchedulable::PreprocessCpuAffinity(aInfo.iCpuAffinity); |
|
116 aGroup->AddToEnumerateList(); |
|
117 aGroup->InitLbInfo(); |
83 return KErrNone; |
118 return KErrNone; |
84 } |
119 } |
85 |
120 |
86 |
121 |
87 /** Destroy a thread group |
122 /** Destroy a thread group |
96 */ |
131 */ |
97 EXPORT_C void NKern::GroupDestroy(NThreadGroup* aGroup) |
132 EXPORT_C void NKern::GroupDestroy(NThreadGroup* aGroup) |
98 { |
133 { |
99 NKern::ThreadEnterCS(); |
134 NKern::ThreadEnterCS(); |
100 aGroup->DetachTiedEvents(); |
135 aGroup->DetachTiedEvents(); |
|
136 NKern::Lock(); |
|
137 aGroup->AcqSLock(); |
|
138 if (aGroup->iLbLink.iNext) |
|
139 aGroup->LbUnlink(); |
|
140 aGroup->RelSLock(); |
|
141 aGroup->DropRef(); |
|
142 NKern::Unlock(); |
101 NKern::ThreadLeaveCS(); |
143 NKern::ThreadLeaveCS(); |
102 } |
144 } |
103 |
145 |
104 |
146 |
105 /****************************************************************************** |
147 /****************************************************************************** |
158 iSuspendCount = 0; |
200 iSuspendCount = 0; |
159 iStackBase = 0; |
201 iStackBase = 0; |
160 iStackSize = 0; |
202 iStackSize = 0; |
161 iExtraContext = 0; |
203 iExtraContext = 0; |
162 iExtraContextSize = 0; |
204 iExtraContextSize = 0; |
|
205 iCoreCycling = 0; |
|
206 iRebalanceAttr = 0; |
|
207 iNThreadBaseSpare4c = 0; |
|
208 iNThreadBaseSpare4d = 0; |
|
209 iNThreadBaseSpare5 = 0; |
163 iNThreadBaseSpare6 = 0; |
210 iNThreadBaseSpare6 = 0; |
164 iNThreadBaseSpare7 = 0; |
211 iNThreadBaseSpare7 = 0; |
165 iNThreadBaseSpare8 = 0; |
212 iNThreadBaseSpare8 = 0; |
166 iNThreadBaseSpare9 = 0; |
213 iNThreadBaseSpare9 = 0; |
167 |
|
168 // KILL |
|
169 iTag = 0; |
|
170 iVemsData = 0; |
|
171 } |
214 } |
172 |
215 |
173 TInt NThreadBase::Create(SNThreadCreateInfo& aInfo, TBool aInitial) |
216 TInt NThreadBase::Create(SNThreadCreateInfo& aInfo, TBool aInitial) |
174 { |
217 { |
175 __KTRACE_OPT(KNKERN,DEBUGPRINT(">NThreadBase::Create %08x(%08x,%d)", this, &aInfo, aInitial)); |
218 __KTRACE_OPT(KNKERN,DEBUGPRINT(">NThreadBase::Create %08x(%08x,%d)", this, &aInfo, aInitial)); |
183 iStackSize=aInfo.iStackSize; |
226 iStackSize=aInfo.iStackSize; |
184 iTimeslice=(aInfo.iTimeslice>0)?aInfo.iTimeslice:-1; |
227 iTimeslice=(aInfo.iTimeslice>0)?aInfo.iTimeslice:-1; |
185 iTime=iTimeslice; |
228 iTime=iTimeslice; |
186 iPriority=TUint8(aInfo.iPriority); |
229 iPriority=TUint8(aInfo.iPriority); |
187 iBasePri=TUint8(aInfo.iPriority); |
230 iBasePri=TUint8(aInfo.iPriority); |
188 iCpuAffinity = aInfo.iCpuAffinity; |
231 iNominalPri=TUint8(aInfo.iPriority); |
|
232 iCpuAffinity = NSchedulable::PreprocessCpuAffinity(aInfo.iCpuAffinity); |
189 iHandlers = aInfo.iHandlers ? aInfo.iHandlers : &NThread_Default_Handlers; |
233 iHandlers = aInfo.iHandlers ? aInfo.iHandlers : &NThread_Default_Handlers; |
190 iFastExecTable=aInfo.iFastExecTable?aInfo.iFastExecTable:&DefaultFastExecTable; |
234 iFastExecTable=aInfo.iFastExecTable?aInfo.iFastExecTable:&DefaultFastExecTable; |
191 iSlowExecTable=(aInfo.iSlowExecTable?aInfo.iSlowExecTable:&DefaultSlowExecTable)->iEntries; |
235 iSlowExecTable=(aInfo.iSlowExecTable?aInfo.iSlowExecTable:&DefaultSlowExecTable)->iEntries; |
192 i_ThrdAttr=(TUint8)aInfo.iAttributes; |
236 i_ThrdAttr=(TUint8)aInfo.iAttributes; |
193 if (aInitial) |
237 if (aInitial) |
196 iLastCpu = (TUint8)ss.iCpuNum; |
240 iLastCpu = (TUint8)ss.iCpuNum; |
197 iReady = (TUint8)(iLastCpu | EReadyOffset); |
241 iReady = (TUint8)(iLastCpu | EReadyOffset); |
198 iCurrent = iReady; |
242 iCurrent = iReady; |
199 iCpuAffinity = iLastCpu; |
243 iCpuAffinity = iLastCpu; |
200 iEventState = (iLastCpu<<EEventCpuShift) | (iLastCpu<<EThreadCpuShift); |
244 iEventState = (iLastCpu<<EEventCpuShift) | (iLastCpu<<EThreadCpuShift); |
201 ss.Add(this); |
245 ss.SSAddEntry(this); |
202 i_NThread_Initial = TRUE; |
246 i_NThread_Initial = TRUE; |
|
247 iACount = 1; |
203 ss.iInitialThread = (NThread*)this; |
248 ss.iInitialThread = (NThread*)this; |
204 NKern::Unlock(); // now that current thread is defined |
249 NKern::Unlock(); // now that current thread is defined |
205 } |
250 } |
206 else |
251 else |
207 { |
252 { |
208 iSuspendCount = 1; |
253 iSuspendCount = 1; |
209 iSuspended = 1; |
254 iSuspended = 1; |
210 TInt ecpu; |
255 iEventState = 0; |
211 if (iCpuAffinity & NTHREADBASE_CPU_AFFINITY_MASK) |
|
212 { |
|
213 ecpu = __e32_find_ls1_32(iCpuAffinity); |
|
214 if (ecpu >= TheScheduler.iNumCpus) |
|
215 ecpu = 0; // FIXME: Inactive CPU? |
|
216 } |
|
217 else |
|
218 ecpu = iCpuAffinity; |
|
219 iEventState = (ecpu<<EEventCpuShift) | (ecpu<<EThreadCpuShift); |
|
220 if (aInfo.iGroup) |
256 if (aInfo.iGroup) |
221 { |
257 { |
222 NKern::Lock(); |
258 NKern::Lock(); |
223 AcqSLock(); |
259 AcqSLock(); |
224 aInfo.iGroup->AcqSLock(); |
260 aInfo.iGroup->AcqSLock(); |
245 void NThread_Default_Exception_Handler(TAny* aContext, NThread*) |
281 void NThread_Default_Exception_Handler(TAny* aContext, NThread*) |
246 { |
282 { |
247 ExcFault(aContext); |
283 ExcFault(aContext); |
248 } |
284 } |
249 |
285 |
|
286 // |
|
287 // Destroy a thread before it has ever run |
|
288 // Must be called before first resumption of thread |
|
289 // |
|
290 void NThread::Stillborn() |
|
291 { |
|
292 __NK_ASSERT_ALWAYS(iACount==0); // ensure thread has never been resumed |
|
293 NKern::Lock(); |
|
294 RemoveFromEnumerateList(); |
|
295 NKern::Unlock(); |
|
296 } |
|
297 |
|
298 |
250 |
299 |
251 /** Create a nanothread. |
300 /** Create a nanothread. |
252 |
301 |
253 This function is intended to be used by the EPOC kernel and by personality |
302 This function is intended to be used by the EPOC kernel and by personality |
254 layers. A nanothread may not use most of the functions available to normal |
303 layers. A nanothread may not use most of the functions available to normal |
268 { |
317 { |
269 CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadCreate"); |
318 CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadCreate"); |
270 return aThread->Create(aInfo,FALSE); |
319 return aThread->Create(aInfo,FALSE); |
271 } |
320 } |
272 |
321 |
273 // User-mode callbacks |
322 |
274 |
323 /****************************************************************************** |
|
324 * User-mode callbacks |
|
325 ******************************************************************************/ |
275 TUserModeCallback::TUserModeCallback(TUserModeCallbackFunc aFunc) |
326 TUserModeCallback::TUserModeCallback(TUserModeCallbackFunc aFunc) |
276 : iNext(KUserModeCallbackUnqueued), |
327 : iNext(KUserModeCallbackUnqueued), |
277 iFunc(aFunc) |
328 iFunc(aFunc) |
278 { |
329 { |
279 } |
330 } |
326 __NK_ASSERT_DEBUG(((TUint)destListStart & 3) == 0); // dest thread must not die |
377 __NK_ASSERT_DEBUG(((TUint)destListStart & 3) == 0); // dest thread must not die |
327 sourceListEnd->iNext = destListStart; |
378 sourceListEnd->iNext = destListStart; |
328 } while (!__e32_atomic_cas_ord_ptr(&aDestThread->iUserModeCallbacks, &destListStart, sourceListStart)); |
379 } while (!__e32_atomic_cas_ord_ptr(&aDestThread->iUserModeCallbacks, &destListStart, sourceListStart)); |
329 NKern::Unlock(); |
380 NKern::Unlock(); |
330 } |
381 } |
|
382 |
331 |
383 |
332 /** Initialise the null thread |
384 /** Initialise the null thread |
333 @internalComponent |
385 @internalComponent |
334 */ |
386 */ |
335 void NKern::Init(NThread* aThread, SNThreadCreateInfo& aInfo) |
387 void NKern::Init(NThread* aThread, SNThreadCreateInfo& aInfo) |