|
1 // Copyright (c) 2006-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 // e32test\nkernsa\nkutils.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <nktest/nkutils.h> |
|
19 |
|
20 extern TDfcQue* CleanupDfcQ; |
|
21 |
|
22 class NThreadX : public NThread |
|
23 { |
|
24 public: |
|
25 NThreadX(); |
|
26 static void KillDfcFn(TAny*); |
|
27 static TDfc* ExitHandler(NThread* aThread); |
|
28 static void ExceptionHandler(TAny* aPtr, NThread* aThread); |
|
29 static void SignalSemaphoreOnExit(TAny* aP, NThread* aT, TInt aC); |
|
30 public: |
|
31 TDfc iKillDfc; |
|
32 TExitFunc iExitFunc; |
|
33 TAny* iExitParam; |
|
34 }; |
|
35 |
|
36 extern const SNThreadHandlers ThreadHandlers = |
|
37 { |
|
38 &NThreadX::ExitHandler, |
|
39 NTHREAD_DEFAULT_STATE_HANDLER, |
|
40 &NThreadX::ExceptionHandler, |
|
41 0 |
|
42 }; |
|
43 |
|
44 NThreadX::NThreadX() |
|
45 : iKillDfc(&KillDfcFn, this, 1), iExitFunc(0) |
|
46 { |
|
47 } |
|
48 |
|
49 void NThreadX::KillDfcFn(TAny* a) |
|
50 { |
|
51 NThreadX* t = (NThreadX*)a; |
|
52 TExitFunc f = t->iExitFunc; |
|
53 TAny* p = t->iExitParam; |
|
54 if (f) |
|
55 (*f)(p, t, 1); |
|
56 #ifdef __SMP__ |
|
57 free((TAny*)t->iNThreadBaseSpare8); |
|
58 #else |
|
59 free((TAny*)t->iSpare8); |
|
60 #endif |
|
61 free((TAny*)t->iStackBase); |
|
62 free(t); |
|
63 if (f) |
|
64 (*f)(p, t, 2); |
|
65 } |
|
66 |
|
67 TDfc* NThreadX::ExitHandler(NThread* aT) |
|
68 { |
|
69 NThreadX* t = (NThreadX*)aT; |
|
70 if (t->iExitFunc) |
|
71 (*t->iExitFunc)(t->iExitParam, t, 0); |
|
72 return &t->iKillDfc; |
|
73 } |
|
74 |
|
75 extern "C" void ExcFault(TAny*); |
|
76 void NThreadX::ExceptionHandler(TAny* aPtr, NThread*) |
|
77 { |
|
78 NKern::DisableAllInterrupts(); |
|
79 ExcFault(aPtr); |
|
80 } |
|
81 |
|
82 extern "C" unsigned int strlen(const char*); |
|
83 |
|
84 NThread* CreateThread(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TBool aResume, TInt aTimeslice, TExitFunc aExitFunc, TAny* aExitParam, TUint32 aCpuAffinity, NThreadGroup* aGroup) |
|
85 { |
|
86 __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateThread %s pri %d", aName, aPri)); |
|
87 TInt nlen = (TInt)strlen(aName); |
|
88 NThreadX* t = new NThreadX; |
|
89 TAny* stack = malloc(KStackSize); |
|
90 memset(stack, 0xee, KStackSize); |
|
91 TAny* namebuf = malloc(nlen+1); |
|
92 memcpy(namebuf, aName, nlen+1); |
|
93 __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateThread -> thread at %08x stack %08x", t, stack)); |
|
94 |
|
95 SNThreadCreateInfo info; |
|
96 |
|
97 info.iFunction = aFunc; |
|
98 info.iStackBase = stack; |
|
99 info.iStackSize = KStackSize; |
|
100 info.iPriority = aPri; |
|
101 info.iTimeslice = aTimeslice; |
|
102 info.iAttributes = 0; |
|
103 info.iHandlers = &ThreadHandlers; |
|
104 info.iFastExecTable = 0; |
|
105 info.iSlowExecTable = 0; |
|
106 info.iParameterBlock = (const TUint32*)aParams; |
|
107 info.iParameterBlockSize = aPSize; |
|
108 #ifdef __SMP__ |
|
109 info.iCpuAffinity = aCpuAffinity; |
|
110 info.iGroup = aGroup; |
|
111 #endif |
|
112 |
|
113 TInt r = NKern::ThreadCreate(t, info); |
|
114 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
115 #ifdef __SMP__ |
|
116 t->iNThreadBaseSpare8 = (TUint32)namebuf; |
|
117 #else |
|
118 t->iSpare8 = (TUint32)namebuf; |
|
119 #endif |
|
120 t->iKillDfc.SetDfcQ(CleanupDfcQ); |
|
121 t->iExitFunc = aExitFunc; |
|
122 t->iExitParam = aExitParam; |
|
123 if (aResume) |
|
124 NKern::ThreadResume(t); |
|
125 return t; |
|
126 } |
|
127 |
|
128 void NThreadX::SignalSemaphoreOnExit(TAny* aP, NThread* aT, TInt aC) |
|
129 { |
|
130 NFastSemaphore* s = (NFastSemaphore*)aP; |
|
131 (void)aT; |
|
132 if (aC==EAfterFree) |
|
133 NKern::FSSignal(s); |
|
134 } |
|
135 |
|
136 NThread* CreateThreadSignalOnExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, NFastSemaphore* aExitSem, TUint32 aCpuAffinity, NThreadGroup* aGroup) |
|
137 { |
|
138 return CreateThread(aName, aFunc, aPri, aParams, aPSize, TRUE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, aExitSem, aCpuAffinity, aGroup); |
|
139 } |
|
140 |
|
141 NThread* CreateUnresumedThreadSignalOnExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, NFastSemaphore* aExitSem, TUint32 aCpuAffinity, NThreadGroup* aGroup) |
|
142 { |
|
143 return CreateThread(aName, aFunc, aPri, aParams, aPSize, FALSE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, aExitSem, aCpuAffinity, aGroup); |
|
144 } |
|
145 |
|
146 void CreateThreadAndWaitForExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, TUint32 aCpuAffinity, NThreadGroup* aGroup) |
|
147 { |
|
148 NFastSemaphore s(0); |
|
149 CreateThread(aName, aFunc, aPri, aParams, aPSize, TRUE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, &s, aCpuAffinity, aGroup); |
|
150 NKern::FSWait(&s); |
|
151 } |
|
152 |
|
153 TDfcQue* CreateDfcQ(const char* aName, TInt aPri, TUint32 aCpuAffinity, NThreadGroup* aGroup) |
|
154 { |
|
155 __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateDfcQ %s pri %d cpu %08x", aName, aPri, aCpuAffinity)); |
|
156 __KTRACE_OPT(KTHREAD,DEBUGPRINT("NKern::CurrentThread() = %08x\n", NKern::CurrentThread())); |
|
157 TDfcQue* q = new TDfcQue; |
|
158 __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateDfcQ -> %08x", q)); |
|
159 NThread* t = CreateThread(aName, &TDfcQue::ThreadFunction, aPri, q, 0, FALSE, KTimeslice, 0, 0, aCpuAffinity, aGroup); |
|
160 q->iThread = t; |
|
161 NKern::ThreadResume(t); |
|
162 return q; |
|
163 } |
|
164 |
|
165 void killDfcFn(TAny* aPtr) |
|
166 { |
|
167 TDfcQue* q = (TDfcQue*)aPtr; |
|
168 delete q; |
|
169 NKern::Exit(); |
|
170 } |
|
171 |
|
172 void DestroyDfcQ(TDfcQue* aQ) |
|
173 { |
|
174 NFastSemaphore exitSem(0); |
|
175 TDfc killDfc(&killDfcFn, aQ, aQ, 0); |
|
176 NThreadX* t = (NThreadX*)aQ->iThread; |
|
177 t->iExitFunc = &NThreadX::SignalSemaphoreOnExit; |
|
178 t->iExitParam = &exitSem; |
|
179 killDfc.Enque(); |
|
180 NKern::FSWait(&exitSem); |
|
181 } |
|
182 |
|
183 #ifdef __SMP__ |
|
184 class NKTest |
|
185 { |
|
186 public: |
|
187 static TInt FSWait(NFastSemaphore* aS, TUint32 aTimeout); |
|
188 }; |
|
189 |
|
190 TInt WaitWithTimeout(NFastSemaphore* aS, TUint32 aTimeout) |
|
191 { |
|
192 return NKTest::FSWait(aS, aTimeout); |
|
193 } |
|
194 |
|
195 TInt NKTest::FSWait(NFastSemaphore* aS, TUint32 aTimeout) |
|
196 { |
|
197 NThreadBase* pC = NKern::LockC(); |
|
198 pC->iWaitState.SetUpWait(NThreadBase::EWaitFastSemaphore, 0, aS, aTimeout); |
|
199 if (aS->Dec(pC)) // full barrier |
|
200 pC->iWaitState.CancelWait(); // don't have to wait |
|
201 else |
|
202 RescheduleNeeded(); // have to wait |
|
203 NKern::PreemptionPoint(); |
|
204 TInt r = pC->iWaitState.iWtC.iRetVal; |
|
205 NKern::Unlock(); |
|
206 return r; |
|
207 } |
|
208 #else |
|
209 TInt WaitWithTimeout(NFastSemaphore* aS, TUint32 aTimeout) |
|
210 { |
|
211 NThreadBase* pC = NKern::LockC(); |
|
212 if (--aS->iCount < 0) |
|
213 { |
|
214 NKern::NanoBlock(aTimeout, NThreadBase::EWaitFastSemaphore, aS); |
|
215 } |
|
216 NKern::PreemptionPoint(); |
|
217 TInt r = pC->iReturnValue; |
|
218 if (r == KErrNone) |
|
219 pC->Release(KErrNone); // cancel the timer on normal completion |
|
220 NKern::Unlock(); |
|
221 return r; |
|
222 } |
|
223 #endif |
|
224 |
|
225 void FMWaitFull(NFastMutex* aMutex) |
|
226 { |
|
227 NKern::Lock(); |
|
228 aMutex->Wait(); |
|
229 NKern::Unlock(); |
|
230 } |
|
231 |
|
232 void FMSignalFull(NFastMutex* aMutex) |
|
233 { |
|
234 NKern::Lock(); |
|
235 aMutex->Signal(); |
|
236 NKern::Unlock(); |
|
237 } |
|
238 |
|
239 void WaitForRequest(NRequestStatus& aStatus) |
|
240 { |
|
241 TInt n = -1; |
|
242 do { |
|
243 ++n; |
|
244 NKern::WaitForAnyRequest(); |
|
245 } while (aStatus == KRequestPending); |
|
246 if (n > 0) |
|
247 NKern::ThreadRequestSignal(0, n); |
|
248 } |
|
249 |
|
250 |
|
251 extern "C" { |
|
252 void SpinWait(TUint32 aTicks) |
|
253 { |
|
254 TUint32 tc = NKern::TickCount() + aTicks; |
|
255 TUint32 x; |
|
256 do { |
|
257 x = NKern::TickCount(); |
|
258 } while (TInt(x-tc)<0); |
|
259 } |
|
260 } |
|
261 |
|
262 |
|
263 |
|
264 |