0
|
1 |
// Copyright (c) 1994-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\kernel\sprocess.cpp
|
|
15 |
//
|
|
16 |
//
|
|
17 |
|
|
18 |
#include <kernel/kern_priv.h>
|
|
19 |
#include <e32uid.h>
|
|
20 |
|
|
21 |
#define iMState iWaitLink.iSpare1
|
|
22 |
|
|
23 |
_LIT(KDollarLock,"$LOCK");
|
|
24 |
_LIT(KDllDollarLock,"DLL$LOCK");
|
|
25 |
_LIT(KLitMain,"Main");
|
|
26 |
_LIT(KLitKill,"Kill");
|
|
27 |
_LIT(KLitTerminate,"Terminate");
|
|
28 |
|
|
29 |
/********************************************
|
|
30 |
* Process
|
|
31 |
********************************************/
|
|
32 |
DProcess::DProcess()
|
|
33 |
: iPriority(EProcPriorityForeground),
|
|
34 |
iExitType((TUint8)EExitPending), iGeneration(1), iFlags(KProcessFlagJustInTime),
|
|
35 |
iDynamicCode(8, _FOFF(SCodeSegEntry, iSeg), 2*256)
|
|
36 |
{
|
|
37 |
//reserve slot 0 for later use for the command line
|
|
38 |
iEnvironmentData[0] = EBinaryData;
|
|
39 |
}
|
|
40 |
|
|
41 |
DProcess::~DProcess()
|
|
42 |
{
|
|
43 |
delete iCommandLine;
|
|
44 |
//delete any process parameters given to this process when it was created
|
|
45 |
TInt i;
|
|
46 |
for (i = 0; i < KArgIndex; ++i)
|
|
47 |
{
|
|
48 |
//if the value is a pointer to a buffer, delete it
|
|
49 |
//if its a pointer to an object, close it
|
|
50 |
TInt data = iEnvironmentData[i]&~3;
|
|
51 |
|
|
52 |
if (iEnvironmentData[i] & EBinaryData)
|
|
53 |
{
|
|
54 |
delete (HBuf8*)(data);
|
|
55 |
}
|
|
56 |
else if (iEnvironmentData[i] & EHandle)
|
|
57 |
{
|
|
58 |
((DObject*)data)->Close(NULL);
|
|
59 |
}
|
|
60 |
}
|
|
61 |
|
|
62 |
}
|
|
63 |
|
|
64 |
void DProcess::Destruct()
|
|
65 |
{
|
|
66 |
}
|
|
67 |
|
|
68 |
void DProcess::DoAppendName(TDes& aName)
|
|
69 |
{
|
|
70 |
DObject::DoAppendName(aName);
|
|
71 |
aName.Append('[');
|
|
72 |
aName.AppendNumFixedWidth(iUids.iUid[2].iUid,EHex,8);
|
|
73 |
aName.Append(']');
|
|
74 |
aName.AppendNumFixedWidth(iGeneration,EDecimal,4);
|
|
75 |
}
|
|
76 |
|
|
77 |
TInt NextGeneration(const TDesC& aName, TUid aUid)
|
|
78 |
//
|
|
79 |
// Return the next generation number for the process
|
|
80 |
//
|
|
81 |
{
|
|
82 |
|
|
83 |
const TInt KNameSuffixLen = 14; // Number of chars after root name, see DoAppendName
|
|
84 |
|
|
85 |
__KTRACE_OPT(KPROC,Kern::Printf("DProcess::NextGeneration %S 0x%08x", &aName, aUid.iUid));
|
|
86 |
TInt gen=0;
|
|
87 |
DObjectCon& processes=*K::Containers[EProcess];
|
|
88 |
TKName name;
|
|
89 |
processes.Wait();
|
|
90 |
for (TInt i = 0 ; i < processes.Count() ; ++i)
|
|
91 |
{
|
|
92 |
DProcess* pP=(DProcess*)processes[i];
|
|
93 |
if (pP->iAccessCount > 0 && aUid.iUid == pP->iUids.iUid[2].iUid && pP->NameBuf())
|
|
94 |
{
|
|
95 |
pP->Name(name);
|
|
96 |
if (name.Length() > KNameSuffixLen)
|
|
97 |
{
|
|
98 |
TPtrC rootName = name.Left(name.Length() - KNameSuffixLen);
|
|
99 |
if (aName.CompareF(rootName) == 0 && pP->iAccessCount > 0)
|
|
100 |
{
|
|
101 |
if (pP->iGeneration>gen)
|
|
102 |
gen=pP->iGeneration;
|
|
103 |
}
|
|
104 |
}
|
|
105 |
}
|
|
106 |
}
|
|
107 |
processes.Signal();
|
|
108 |
__KTRACE_OPT(KPROC,Kern::Printf("DProcess generation %d",gen+1));
|
|
109 |
return(gen+1);
|
|
110 |
}
|
|
111 |
|
|
112 |
__ASSERT_COMPILE(ECapability_Limit<=32); // Kernel's iCaps caps below assumes this
|
|
113 |
|
|
114 |
|
|
115 |
TInt DProcess::SetPaging(const TProcessCreateInfo& aInfo)
|
|
116 |
{// Default implementation that only verifies flags, this virtual method
|
|
117 |
// is overridden in memory models that support paging.
|
|
118 |
if (aInfo.iFlags & TProcessCreateInfo::EDataPagingMask ==
|
|
119 |
TProcessCreateInfo::EDataPagingMask)
|
|
120 |
{
|
|
121 |
return KErrCorrupt;
|
|
122 |
}
|
|
123 |
return KErrNone;
|
|
124 |
}
|
|
125 |
|
|
126 |
|
|
127 |
TInt DProcess::Create(TBool aKernelProcess, TProcessCreateInfo& aInfo, HBuf* aCommandLine)
|
|
128 |
{
|
|
129 |
__KTRACE_OPT(KBOOT,Kern::Printf("DProcess::Create"));
|
|
130 |
|
|
131 |
TInt r=KErrNone;
|
|
132 |
iCommandLine=aCommandLine; // do this first to prevent memory leak if error occurs
|
|
133 |
TPtrC f=aInfo.iFileName.Mid(aInfo.iRootNameOffset,aInfo.iRootNameLength);
|
|
134 |
r=SetName(&f);
|
|
135 |
if (r!=KErrNone)
|
|
136 |
return r;
|
|
137 |
|
|
138 |
// Verify and save any data paging attributes.
|
|
139 |
SetPaging(aInfo);
|
|
140 |
|
|
141 |
iUids=aInfo.iUids;
|
|
142 |
iS=aInfo.iS;
|
|
143 |
iDebugAttributes = (TUint8)aInfo.iDebugAttributes;
|
|
144 |
if (!aKernelProcess)
|
|
145 |
{
|
|
146 |
iPriority=0;
|
|
147 |
TInt p=ConvertPriority(aInfo.iPriority);
|
|
148 |
if (p<0)
|
|
149 |
return KErrArgument;
|
|
150 |
iPriority=p;
|
|
151 |
iGeneration=NextGeneration(f,iUids.iUid[2]);
|
|
152 |
}
|
|
153 |
else
|
|
154 |
{
|
|
155 |
iPriority = EProcPrioritySystemServer3;
|
|
156 |
iFlags |= KProcessFlagSystemPermanent|KProcessFlagSystemCritical;
|
|
157 |
}
|
|
158 |
#ifdef BTRACE_THREAD_PRIORITY
|
|
159 |
BTrace8(BTrace::EThreadPriority,BTrace::EProcessPriority,this,iPriority);
|
|
160 |
#endif
|
|
161 |
iId = K::NewId();
|
|
162 |
iCreatorId = iId; // Initialise as self for safety because creator has special capabilities
|
|
163 |
if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecProcessIsolation)
|
|
164 |
{
|
|
165 |
if(aInfo.iSecurityZone==KSecurityZoneUnique)
|
|
166 |
iSecurityZone=iId;
|
|
167 |
else
|
|
168 |
iSecurityZone=aInfo.iSecurityZone;
|
|
169 |
}
|
|
170 |
else
|
|
171 |
iSecurityZone=KSecurityZoneLegacyCode;
|
|
172 |
|
|
173 |
r=K::MutexCreate((DMutex*&)iProcessLock, KDollarLock, this, EFalse, KMutexOrdProcessLock);
|
|
174 |
__KTRACE_OPT(KPROC,Kern::Printf("Lock mutex created, %d",r));
|
|
175 |
if (r!=KErrNone)
|
|
176 |
return r;
|
|
177 |
if (!aKernelProcess)
|
|
178 |
{
|
|
179 |
r=K::MutexCreate((DMutex*&)iDllLock, KDllDollarLock, this, EFalse, KMutexOrdUser);
|
|
180 |
if (r!=KErrNone)
|
|
181 |
return r;
|
|
182 |
}
|
|
183 |
r=DoCreate(aKernelProcess,aInfo);
|
|
184 |
if (r!=KErrNone)
|
|
185 |
return r;
|
|
186 |
__KTRACE_OPT(KPROC,Kern::Printf("Process attributes %08x",iAttributes));
|
|
187 |
iAttributes |= EBeingLoaded;
|
|
188 |
|
|
189 |
#ifdef __DEBUGGER_SUPPORT__
|
|
190 |
// Send new process notification. Note that the creator thread can not always
|
|
191 |
// be figured out. It could have been killed atfer requesting the loader to
|
|
192 |
// create the process or the process could be created by a kernel thread.
|
|
193 |
NKern::LockSystem();
|
|
194 |
|
|
195 |
DThread* creator = (DThread*)TheCurrentThread->ObjectFromHandle(aInfo.iClientHandle,EThread);
|
|
196 |
|
|
197 |
if (creator && (creator->Open() != KErrNone))
|
|
198 |
creator = NULL;
|
|
199 |
|
|
200 |
NKern::UnlockSystem();
|
|
201 |
|
|
202 |
__DEBUG_EVENT2(EEventAddProcess, this, creator);
|
|
203 |
|
|
204 |
if (creator)
|
|
205 |
creator->Close(NULL);
|
|
206 |
#endif
|
|
207 |
|
|
208 |
#ifdef BTRACE_THREAD_IDENTIFICATION
|
|
209 |
BTrace4(BTrace::EThreadIdentification,BTrace::EProcessCreate,this);
|
|
210 |
#endif
|
|
211 |
|
|
212 |
iTempCodeSeg=(DCodeSeg*)aInfo.iHandle;
|
|
213 |
if (iTempCodeSeg)
|
|
214 |
{
|
|
215 |
if (iTempCodeSeg->iExeCodeSeg!=iTempCodeSeg)
|
|
216 |
return KErrNotSupported;
|
|
217 |
iTempCodeSeg->WaitCheckedOpen();
|
|
218 |
r=AttachExistingCodeSeg(aInfo); // doesn't map the code in - Loaded() does this
|
|
219 |
if (r!=KErrNone)
|
|
220 |
return r;
|
|
221 |
}
|
|
222 |
else
|
|
223 |
{
|
|
224 |
iTempCodeSeg=M::NewCodeSeg(aInfo);
|
|
225 |
if (!iTempCodeSeg)
|
|
226 |
return KErrNoMemory;
|
|
227 |
iTempCodeSeg->iExeCodeSeg=iTempCodeSeg;
|
|
228 |
r=iTempCodeSeg->Create(aInfo,this);
|
|
229 |
if (r!=KErrNone)
|
|
230 |
return r;
|
|
231 |
iTempCodeSeg->WaitCheckedOpen();
|
|
232 |
aInfo.iHandle=iTempCodeSeg;
|
|
233 |
}
|
|
234 |
if (!aKernelProcess)
|
|
235 |
{
|
|
236 |
DThread* pT=NULL;
|
|
237 |
SStdEpocThreadCreateInfo t;
|
|
238 |
t.iType=EThreadUser;
|
|
239 |
t.iFunction=(TThreadFunction)aInfo.iFileEntryPoint; // kernel will call veneer, veneer will call this
|
|
240 |
t.iPtr=NULL;
|
|
241 |
t.iSupervisorStack=NULL;
|
|
242 |
t.iSupervisorStackSize=0; // zero means use default value
|
|
243 |
t.iUserStack=NULL;
|
|
244 |
t.iUserStackSize=aInfo.iStackSize;
|
|
245 |
t.iInitialThreadPriority=EThrdPriorityNormal;
|
|
246 |
t.iName.Set(KLitMain);
|
|
247 |
t.iAllocator=NULL;
|
|
248 |
t.iHeapInitialSize=aInfo.iHeapSizeMin;
|
|
249 |
t.iHeapMaxSize=aInfo.iHeapSizeMax;
|
|
250 |
t.iTotalSize = sizeof(t);
|
|
251 |
r=NewThread((DThread*&)pT, t, NULL, EOwnerProcess);
|
|
252 |
if (r==KErrNone)
|
|
253 |
pT->iFlags |= KThreadFlagProcessPermanent|KThreadFlagOriginal;
|
|
254 |
iUserThreadsRunning=1;
|
|
255 |
}
|
|
256 |
if (r!=KErrNone)
|
|
257 |
return r;
|
|
258 |
if (!aKernelProcess)
|
|
259 |
r=K::AddObject(this,EProcess);
|
|
260 |
return r;
|
|
261 |
}
|
|
262 |
|
|
263 |
DCodeSeg* DProcess::CodeSeg()
|
|
264 |
{
|
|
265 |
return iCodeSeg ? iCodeSeg : iTempCodeSeg;
|
|
266 |
}
|
|
267 |
|
|
268 |
TInt DProcess::SetPriority(TProcessPriority aPriority)
|
|
269 |
{
|
|
270 |
TInt p=ConvertPriority(aPriority);
|
|
271 |
if (p<0)
|
|
272 |
return KErrArgument;
|
|
273 |
if (iExitType!=EExitPending)
|
|
274 |
return KErrDied;
|
|
275 |
|
|
276 |
__KTRACE_OPT(KPROC,Kern::Printf("Process %O SetPriority(%d)",this,p));
|
|
277 |
TInt r=WaitProcessLock();
|
|
278 |
__KTRACE_FAIL(r,Kern::Printf("PSP: %d",r));
|
|
279 |
if (r!=KErrNone)
|
|
280 |
return KErrDied;
|
|
281 |
#ifdef BTRACE_THREAD_PRIORITY
|
|
282 |
BTrace8(BTrace::EThreadPriority,BTrace::EProcessPriority,this,p);
|
|
283 |
#endif
|
|
284 |
NKern::LockSystem();
|
|
285 |
iPriority=p;
|
|
286 |
SDblQueLink* pLink=iThreadQ.First();
|
|
287 |
while (pLink!=&iThreadQ.iA)
|
|
288 |
{
|
|
289 |
DThread* pT=_LOFF(pLink,DThread,iProcessLink);
|
|
290 |
pT->SetThreadPriority(pT->iThreadPriority);
|
|
291 |
pLink=pLink->iNext;
|
|
292 |
NKern::FlashSystem();
|
|
293 |
}
|
|
294 |
NKern::UnlockSystem();
|
|
295 |
SignalProcessLock();
|
|
296 |
return KErrNone;
|
|
297 |
}
|
|
298 |
|
|
299 |
TInt DProcess::ConvertPriority(TProcessPriority aPriority)
|
|
300 |
{
|
|
301 |
TInt p=-1;
|
|
302 |
switch(aPriority)
|
|
303 |
{
|
|
304 |
case EPriorityLow: p=EProcPriorityLow; break;
|
|
305 |
case EPriorityBackground: p=EProcPriorityBackground; break;
|
|
306 |
case EPriorityForeground: p=EProcPriorityForeground; break;
|
|
307 |
case EPriorityHigh: p=EProcPriorityHigh; break;
|
|
308 |
case EPriorityWindowServer: p=EProcPrioritySystemServer1; break;
|
|
309 |
case EPriorityFileServer: p=EProcPrioritySystemServer2; break;
|
|
310 |
case EPriorityRealTimeServer: p=EProcPriorityRealTimeServer; break;
|
|
311 |
case EPrioritySupervisor: p=EProcPrioritySystemServer3; break;
|
|
312 |
}
|
|
313 |
return p;
|
|
314 |
}
|
|
315 |
|
|
316 |
TInt DProcess::Rename(const TDesC& aName)
|
|
317 |
{
|
|
318 |
if (aName.Length()>KMaxKernelName-KMaxUidName-4)
|
|
319 |
return KErrBadName;
|
|
320 |
TKName n;
|
|
321 |
DObject::BaseName(n); // get current name, without UID and generation number
|
|
322 |
if (n.MatchF(aName)==0)
|
|
323 |
return KErrNone; // new name is the same so nothing to do
|
|
324 |
|
|
325 |
iGeneration = NextGeneration(aName, iUids.iUid[2]);
|
|
326 |
|
|
327 |
__KTRACE_OPT(KTHREAD,Kern::Printf("DProcess::Rename %O to %lS",this,&aName));
|
|
328 |
TInt r = SetName(&aName);
|
|
329 |
#ifdef BTRACE_THREAD_IDENTIFICATION
|
|
330 |
Name(n);
|
|
331 |
BTraceN(BTrace::EThreadIdentification,BTrace::EProcessName,0,this,n.Ptr(),n.Size());
|
|
332 |
#endif
|
|
333 |
|
|
334 |
__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateProcess, this);
|
|
335 |
return(r);
|
|
336 |
}
|
|
337 |
|
|
338 |
void DProcess::Release()
|
|
339 |
{
|
|
340 |
#ifdef __SMP__
|
|
341 |
// delete thread group
|
|
342 |
if (iSMPUnsafeGroup)
|
|
343 |
{
|
|
344 |
NKern::GroupDestroy(iSMPUnsafeGroup);
|
|
345 |
Kern::Free(iSMPUnsafeGroup);
|
|
346 |
}
|
|
347 |
#endif
|
|
348 |
|
|
349 |
// delete handles with lock mutex free
|
|
350 |
__KTRACE_OPT(KPROC,Kern::Printf("Process %O Release()",this));
|
|
351 |
__KTRACE_OPT(KPROC,Kern::Printf("Deleting handles"));
|
|
352 |
iHandles.Close(this);
|
|
353 |
|
|
354 |
// Notify process unloading before code segs are released
|
|
355 |
__DEBUG_EVENT(EEventUnloadingProcess, this);
|
|
356 |
|
|
357 |
__NK_ASSERT_DEBUG(iGarbageList.IsEmpty());
|
|
358 |
|
|
359 |
if (iCodeSeg || iTempCodeSeg)
|
|
360 |
{
|
|
361 |
DCodeSeg::Wait();
|
|
362 |
if (iCodeSeg)
|
|
363 |
RemoveCodeSeg(iCodeSeg, NULL);
|
|
364 |
DCodeSeg* pS = (DCodeSeg*)__e32_atomic_swp_ord_ptr(&iTempCodeSeg, 0);
|
|
365 |
if (pS)
|
|
366 |
pS->CheckedClose();
|
|
367 |
RemoveDllData();
|
|
368 |
DCodeSeg::Signal();
|
|
369 |
}
|
|
370 |
|
|
371 |
__ASSERT_ALWAYS(iDynamicCode.Count()==0, K::Fault(K::ECodeStillMapped));
|
|
372 |
iDynamicCode.Close();
|
|
373 |
|
|
374 |
__KTRACE_OPT(KPROC,Kern::Printf("Closing DLL$LOCK mutex"));
|
|
375 |
Kern::SafeClose((DObject*&)iDllLock,this);
|
|
376 |
|
|
377 |
__KTRACE_OPT(KPROC,Kern::Printf("Closing owning process"));
|
|
378 |
Kern::SafeClose((DObject*&)iOwningProcess,NULL);
|
|
379 |
|
|
380 |
__KTRACE_OPT(KPROC,Kern::Printf("Closing DataBssStack chunk"));
|
|
381 |
Kern::SafeClose((DObject*&)iDataBssStackChunk,this);
|
|
382 |
|
|
383 |
NKern::LockSystem();
|
|
384 |
iFinalReleaseFlag = ETrue;
|
|
385 |
if (iProcessLock)
|
|
386 |
iProcessLock->Wait(); // this will get released when the lock mutex is deleted
|
|
387 |
NKern::UnlockSystem();
|
|
388 |
|
|
389 |
__KTRACE_OPT(KPROC,Kern::Printf("Calling FinalRelease()"));
|
|
390 |
// Call FinalRelease() with process $LOCK mutex held (if it exists)
|
|
391 |
// and don't ever release the mutex afterwards.
|
|
392 |
FinalRelease();
|
|
393 |
|
|
394 |
__KTRACE_OPT(KPROC,Kern::Printf("Closing $LOCK mutex"));
|
|
395 |
Kern::SafeClose((DObject*&)iProcessLock,this);
|
|
396 |
|
|
397 |
// Notify process removal before closing process
|
|
398 |
__DEBUG_EVENT(EEventRemoveProcess, this);
|
|
399 |
|
|
400 |
#ifdef BTRACE_THREAD_IDENTIFICATION
|
|
401 |
BTrace4(BTrace::EThreadIdentification,BTrace::EProcessDestroy,this);
|
|
402 |
#endif
|
|
403 |
|
|
404 |
// Kill any processes which we created but have not resumed
|
|
405 |
NKern::LockSystem(); // In case we died in the middle of DProcess::Resume()
|
|
406 |
NKern::UnlockSystem();
|
|
407 |
for(;;)
|
|
408 |
{
|
|
409 |
DObjectCon& processes=*K::Containers[EProcess];
|
|
410 |
processes.Wait();
|
|
411 |
DProcess* zombie=NULL;
|
|
412 |
TInt c=processes.Count();
|
|
413 |
for (TInt i=0; i<c; i++)
|
|
414 |
{
|
|
415 |
DProcess* pP=(DProcess*)processes[i];
|
|
416 |
if (pP->iCreatorId==iId && pP!=this && pP->Open()==KErrNone)
|
|
417 |
{
|
|
418 |
zombie = pP;
|
|
419 |
break;
|
|
420 |
}
|
|
421 |
}
|
|
422 |
processes.Signal();
|
|
423 |
if(!zombie)
|
|
424 |
break;
|
|
425 |
__KTRACE_OPT(KPROC,Kern::Printf("Killing zombie process %O",zombie));
|
|
426 |
zombie->iCreatorId=zombie->iId;
|
|
427 |
zombie->Die(EExitPanic,EZombieProcessKilled,KLitKernExec());
|
|
428 |
zombie->Close(0);
|
|
429 |
}
|
|
430 |
|
|
431 |
__KTRACE_OPT(KPROC,Kern::Printf("Closing process"));
|
|
432 |
Close(this);
|
|
433 |
}
|
|
434 |
|
|
435 |
TInt DProcess::WaitProcessLock()
|
|
436 |
{
|
|
437 |
TInt r=KErrGeneral;
|
|
438 |
NKern::LockSystem();
|
|
439 |
if (iProcessLock && !iFinalReleaseFlag) // iProcessLock is deleted during process death
|
|
440 |
{
|
|
441 |
r=iProcessLock->Wait(); // mutex may be resetting just before deletion
|
|
442 |
__KTRACE_FAIL(r,Kern::Printf("PLW: %d",r)); // will return KErrGeneral if mutex is reset
|
|
443 |
}
|
|
444 |
NKern::UnlockSystem();
|
|
445 |
__KTRACE_FAIL(r,Kern::Printf("WPL: %d",r));
|
|
446 |
return r;
|
|
447 |
}
|
|
448 |
|
|
449 |
TInt DProcess::SignalProcessLock()
|
|
450 |
{
|
|
451 |
TInt r=KErrDied;
|
|
452 |
NKern::LockSystem();
|
|
453 |
if (iProcessLock)
|
|
454 |
{
|
|
455 |
iProcessLock->Signal();
|
|
456 |
r=KErrNone;
|
|
457 |
}
|
|
458 |
else
|
|
459 |
NKern::UnlockSystem();
|
|
460 |
__KTRACE_FAIL(r,Kern::Printf("SPL: %d",r));
|
|
461 |
return r;
|
|
462 |
}
|
|
463 |
|
|
464 |
TInt DProcess::Loaded(TProcessCreateInfo& aInfo)
|
|
465 |
//
|
|
466 |
// Confirm that the process has been loaded O.K.
|
|
467 |
//
|
|
468 |
{
|
|
469 |
__KTRACE_OPT(KPROC,Kern::Printf("DProcess::Loaded"));
|
|
470 |
|
|
471 |
//
|
|
472 |
// Update our code segment and dependents
|
|
473 |
//
|
|
474 |
DCodeSeg::Wait();
|
|
475 |
|
|
476 |
TInt r = KErrNone;
|
|
477 |
|
|
478 |
if (!(iTempCodeSeg->iMark & DCodeSeg::EMarkLoaded))
|
|
479 |
{
|
|
480 |
// newly loaded code segment, not another instance of same
|
|
481 |
r = iTempCodeSeg->Loaded(aInfo);
|
|
482 |
}
|
|
483 |
|
|
484 |
if (r == KErrNone)
|
|
485 |
r = OpenDeps();
|
|
486 |
|
|
487 |
DCodeSeg::Signal();
|
|
488 |
|
|
489 |
if (r != KErrNone)
|
|
490 |
return r;
|
|
491 |
|
|
492 |
if (iCodeSeg->iAttr & ECodeSegAttSMPSafe)
|
|
493 |
iSMPUnsafeCount = 0;
|
|
494 |
else
|
|
495 |
{
|
|
496 |
iSMPUnsafeCount = 1;
|
|
497 |
#ifdef __SMP__
|
|
498 |
r = UpdateSMPSafe();
|
|
499 |
if (r != KErrNone)
|
|
500 |
return r;
|
|
501 |
#endif
|
|
502 |
}
|
|
503 |
FirstThread()->iMState=DThread::EReady;
|
|
504 |
SetProtection(DObject::EGlobal);
|
|
505 |
iAttributes &= ~EBeingLoaded;
|
|
506 |
iReentryPoint = iCodeSeg->iEntryPtVeneer;
|
|
507 |
|
|
508 |
// Send loaded process notification.
|
|
509 |
__DEBUG_EVENT(EEventLoadedProcess, this);
|
|
510 |
|
|
511 |
return KErrNone;
|
|
512 |
}
|
|
513 |
|
|
514 |
void DProcess::Resume()
|
|
515 |
//
|
|
516 |
// Resume a newly created process. Idempotent. Enter and return with system locked.
|
|
517 |
//
|
|
518 |
{
|
|
519 |
if (iAttributes&EBeingLoaded)
|
|
520 |
K::PanicCurrentThread(EProcessNotLoaded);
|
|
521 |
if (!(iAttributes&EResumed))
|
|
522 |
{
|
|
523 |
iAttributes|=EResumed;
|
|
524 |
iCreatorId = iId; // Creator loses control over process once it has been resumed
|
|
525 |
FirstThread()->Resume();
|
|
526 |
}
|
|
527 |
}
|
|
528 |
|
|
529 |
void DProcess::Die(TExitType aType, TInt aReason, const TDesC &aCategory)
|
|
530 |
//
|
|
531 |
// Kill a process. Enter and return with system unlocked and calling thread in critical section.
|
|
532 |
//
|
|
533 |
{
|
|
534 |
__KTRACE_OPT(KPROC,Kern::Printf("Process %O Die: %d %d %lS",this,aType,aReason,&aCategory));
|
|
535 |
|
|
536 |
TInt r=WaitProcessLock();
|
|
537 |
if (r!=KErrNone)
|
|
538 |
return; // process already exiting
|
|
539 |
NKern::LockSystem();
|
|
540 |
if (iAttributes&EBeingLoaded)
|
|
541 |
{
|
|
542 |
// Load failed before UserSvr::ProcessLoaded() was called.
|
|
543 |
// The thread is still runnable however, since UserSvr::ProcessCreate() must have succeeded.
|
|
544 |
// We just need to set the thread state so it can be resumed.
|
|
545 |
FirstThread()->iMState=DThread::EReady;
|
|
546 |
}
|
|
547 |
if (iExitType==EExitPending)
|
|
548 |
{
|
|
549 |
iExitType = (TUint8)aType;
|
|
550 |
iExitReason=aReason;
|
|
551 |
if (iExitType==EExitKill)
|
|
552 |
iExitCategory=KLitKill;
|
|
553 |
else if (iExitType==EExitTerminate)
|
|
554 |
iExitCategory=KLitTerminate;
|
|
555 |
else
|
|
556 |
iExitCategory=aCategory;
|
|
557 |
|
|
558 |
if (iExitType!=EExitKill && (iFlags & (KProcessFlagSystemPermanent|KProcessFlagSystemCritical)))
|
|
559 |
K::Fault(K::ESystemProcessPanic);
|
|
560 |
if (iFlags & KProcessFlagSystemPermanent)
|
|
561 |
K::Fault(K::EPermanentProcessExit);
|
|
562 |
|
|
563 |
// Kill all threads; when the last one exits the process will be cleaned up.
|
|
564 |
TBool killMe = KillAllThreads(aType, aReason, aCategory);
|
|
565 |
if (killMe)
|
|
566 |
{
|
|
567 |
DThread* pC=TheCurrentThread;
|
|
568 |
pC->iExitType=(TUint8)iExitType;
|
|
569 |
pC->iExitReason=iExitReason;
|
|
570 |
pC->iExitCategory=iExitCategory;
|
|
571 |
NKern::DeferredExit();
|
|
572 |
}
|
|
573 |
}
|
|
574 |
NKern::UnlockSystem();
|
|
575 |
SignalProcessLock();
|
|
576 |
}
|
|
577 |
|
|
578 |
TBool DProcess::KillAllThreads(TExitType aType, TInt aReason, const TDesC &aCategory)
|
|
579 |
//
|
|
580 |
// Kill all threads in a process. Enter and return with system locked, the process lock held and
|
|
581 |
// calling thread in a critical section. Returns whether the current thread needs to exit too.
|
|
582 |
//
|
|
583 |
{
|
|
584 |
TBool killMe=EFalse;
|
|
585 |
DThread* pC=TheCurrentThread;
|
|
586 |
SDblQueLink* pLink=iThreadQ.First();
|
|
587 |
while (pLink!=&iThreadQ.iA)
|
|
588 |
{
|
|
589 |
DThread* pT=_LOFF(pLink,DThread,iProcessLink);
|
|
590 |
pLink=pLink->iNext;
|
|
591 |
if (pT!=pC)
|
|
592 |
{
|
|
593 |
// Need to stop the current thread being killed as a consequence of killing pT
|
|
594 |
pT->iFlags &= ~(KThreadFlagProcessPermanent|KThreadFlagProcessCritical);
|
|
595 |
pT->Die(aType, aReason, aCategory);
|
|
596 |
}
|
|
597 |
else
|
|
598 |
{
|
|
599 |
killMe=ETrue;
|
|
600 |
NKern::UnlockSystem();
|
|
601 |
}
|
|
602 |
NKern::LockSystem();
|
|
603 |
}
|
|
604 |
return killMe;
|
|
605 |
}
|
|
606 |
|
|
607 |
void DProcess::AddThread(DThread &aThread)
|
|
608 |
{
|
|
609 |
__KTRACE_OPT(KPROC,Kern::Printf("AddThread %O to %O",&aThread,this));
|
|
610 |
iThreadQ.Add(&aThread.iProcessLink);
|
|
611 |
}
|
|
612 |
|
|
613 |
TInt DProcess::NewThread(DThread*& aThread, SThreadCreateInfo& anInfo, TInt* aHandle, TOwnerType aType)
|
|
614 |
{
|
|
615 |
__KTRACE_OPT(KTHREAD,Kern::Printf("NewThread proc %O, func %08x ptr %08x",this,anInfo.iFunction,anInfo.iPtr));
|
|
616 |
__KTRACE_OPT(KTHREAD,Kern::Printf("type %d name %lS pri %d",anInfo.iType,&anInfo.iName,anInfo.iInitialThreadPriority));
|
|
617 |
if (aHandle)
|
|
618 |
*aHandle=0;
|
|
619 |
TInt r=GetNewThread(aThread,anInfo);
|
|
620 |
__KTRACE_FAIL(r,Kern::Printf("GNT: %d",r));
|
|
621 |
DThread* pT=aThread;
|
|
622 |
if (r==KErrNone)
|
|
623 |
{
|
|
624 |
r=pT->Create(anInfo);
|
|
625 |
__KTRACE_FAIL(r,Kern::Printf("NTC: %d",r));
|
|
626 |
if (r==KErrNone && aHandle)
|
|
627 |
{
|
|
628 |
r=K::MakeHandleAndOpen(aType,pT,*aHandle);
|
|
629 |
__KTRACE_FAIL(r,Kern::Printf("NT MHO: %d",r));
|
|
630 |
}
|
|
631 |
if (r==KErrNone)
|
|
632 |
{
|
|
633 |
r=WaitProcessLock();
|
|
634 |
if (r==KErrNone)
|
|
635 |
{
|
|
636 |
NKern::LockSystem();
|
|
637 |
if (iExitType==EExitPending)
|
|
638 |
{
|
|
639 |
AddThread(*pT);
|
|
640 |
pT->iMState=DThread::EReady;
|
|
641 |
// set fully constructed flag here
|
|
642 |
}
|
|
643 |
else
|
|
644 |
r=KErrDied;
|
|
645 |
NKern::UnlockSystem();
|
|
646 |
SignalProcessLock();
|
|
647 |
__KTRACE_FAIL(r,Kern::Printf("NT ADD: %d",r));
|
|
648 |
}
|
|
649 |
else
|
|
650 |
r=KErrDied;
|
|
651 |
}
|
|
652 |
}
|
|
653 |
if (r==KErrNone)
|
|
654 |
{
|
|
655 |
if (anInfo.iType == EThreadUser)
|
|
656 |
{
|
|
657 |
pT->iUserThreadState = DThread::EUserThreadCreated;
|
|
658 |
__e32_atomic_tas_ord32(&iUserThreadsRunning, 1, 1, 0);
|
|
659 |
}
|
|
660 |
#ifdef BTRACE_THREAD_IDENTIFICATION
|
|
661 |
if(BTrace::Filter(BTrace::EThreadIdentification))
|
|
662 |
{
|
|
663 |
DObjectCon* threads=Kern::Containers()[EThread];
|
|
664 |
threads->Wait(); // hold mutex so traces below don't get mixed up with other thread creation traces
|
|
665 |
TKName nameBuf;
|
|
666 |
Name(nameBuf);
|
|
667 |
BTraceN(BTrace::EThreadIdentification,BTrace::EProcessName,&pT->iNThread,this,nameBuf.Ptr(),nameBuf.Size());
|
|
668 |
pT->Name(nameBuf);
|
|
669 |
BTraceN(BTrace::EThreadIdentification,BTrace::EThreadCreate,&pT->iNThread,this,nameBuf.Ptr(),nameBuf.Size());
|
|
670 |
BTrace12(BTrace::EThreadIdentification,BTrace::EThreadId,&pT->iNThread,this,pT->iId);
|
|
671 |
threads->Signal();
|
|
672 |
}
|
|
673 |
#endif
|
|
674 |
__DEBUG_EVENT2(EEventAddThread, pT, TheCurrentThread);
|
|
675 |
}
|
|
676 |
else if (pT)
|
|
677 |
{
|
|
678 |
if (aHandle && *aHandle)
|
|
679 |
{
|
|
680 |
K::HandleClose(*aHandle);
|
|
681 |
*aHandle=0;
|
|
682 |
}
|
|
683 |
pT->Stillborn();
|
|
684 |
aThread=NULL;
|
|
685 |
}
|
|
686 |
__KTRACE_FAIL(r,Kern::Printf("NT: %d",r));
|
|
687 |
return r;
|
|
688 |
}
|
|
689 |
|
|
690 |
void DProcess::Rendezvous(TInt aReason)
|
|
691 |
//
|
|
692 |
// Enter and return with system unlocked and calling thread in critical section.
|
|
693 |
//
|
|
694 |
{
|
|
695 |
TLogon::CompleteAll(iTargetLogons, TLogon::ETargetRendezvous, aReason);
|
|
696 |
}
|
|
697 |
|
|
698 |
TInt DProcess::Logon(TRequestStatus* aStatus, TBool aRendezvous)
|
|
699 |
{
|
|
700 |
TInt r = KErrNoMemory;
|
|
701 |
DThread* pC = TheCurrentThread;
|
|
702 |
__KTRACE_OPT(KTHREAD, Kern::Printf("Thread %O Logon to process %O, status at %08x rdv=%x",
|
|
703 |
pC, this, aStatus, aRendezvous));
|
|
704 |
|
|
705 |
TLogon* pL = new TLogon;
|
|
706 |
if (pL)
|
|
707 |
{
|
|
708 |
TUint32 type = TLogon::ETargetProcess;
|
|
709 |
if (aRendezvous)
|
|
710 |
type |= TLogon::ERendezvous;
|
|
711 |
r = pL->Attach(iTargetLogons, pC, this, aStatus, type);
|
|
712 |
if (r != KErrNone)
|
|
713 |
pL->Close();
|
|
714 |
}
|
|
715 |
|
|
716 |
__KTRACE_OPT(KTHREAD, Kern::Printf("DProcess::Logon ret %d", r));
|
|
717 |
return r;
|
|
718 |
}
|
|
719 |
|
|
720 |
void DProcess::BTracePrime(TInt aCategory)
|
|
721 |
{
|
|
722 |
#ifdef BTRACE_THREAD_IDENTIFICATION
|
|
723 |
if(aCategory==BTrace::EThreadIdentification || aCategory==-1)
|
|
724 |
BTrace4(BTrace::EThreadIdentification,BTrace::EProcessCreate,this);
|
|
725 |
#endif
|
|
726 |
}
|
|
727 |
|
|
728 |
#ifdef __SMP__
|
|
729 |
TInt DProcess::UpdateSMPSafe()
|
|
730 |
{
|
|
731 |
TUint32 config = TheSuperPage().KernelConfigFlags();
|
|
732 |
if (!(config & (EKernelConfigSMPUnsafeCompat|EKernelConfigSMPUnsafeCPU0)) || this == K::TheKernelProcess)
|
|
733 |
return KErrNone;
|
|
734 |
__KTRACE_OPT(KPROC,Kern::Printf("Process %O UpdateSMPSafe count=%d",this,iSMPUnsafeCount));
|
|
735 |
TInt r=WaitProcessLock();
|
|
736 |
(void)r;
|
|
737 |
__NK_ASSERT_DEBUG(r==KErrNone);
|
|
738 |
if ((config & EKernelConfigSMPUnsafeCompat) && !iSMPUnsafeGroup)
|
|
739 |
{
|
|
740 |
SNThreadGroupCreateInfo info;
|
|
741 |
info.iCpuAffinity = KCpuAffinityAny;
|
|
742 |
iSMPUnsafeGroup = (NThreadGroup*)Kern::Alloc(sizeof(NThreadGroup));
|
|
743 |
r = KErrNoMemory;
|
|
744 |
if (iSMPUnsafeGroup)
|
|
745 |
r = NKern::GroupCreate(iSMPUnsafeGroup, info);
|
|
746 |
}
|
|
747 |
if (r==KErrNone)
|
|
748 |
{
|
|
749 |
SDblQueLink* pLink=iThreadQ.First();
|
|
750 |
while (pLink!=&iThreadQ.iA)
|
|
751 |
{
|
|
752 |
DThread* pT=_LOFF(pLink,DThread,iProcessLink);
|
|
753 |
NKern::QueueUserModeCallback(&pT->iNThread, &pT->iSMPSafeCallback);
|
|
754 |
pLink=pLink->iNext;
|
|
755 |
}
|
|
756 |
}
|
|
757 |
SignalProcessLock();
|
|
758 |
return r;
|
|
759 |
}
|
|
760 |
#endif
|
|
761 |
|