kernel/eka/kernel/sprocess.cpp
changeset 0 a41df078684a
child 42 a179b74831c9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/kernel/sprocess.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,761 @@
+// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\kernel\sprocess.cpp
+// 
+//
+
+#include <kernel/kern_priv.h>
+#include <e32uid.h>
+
+#define iMState		iWaitLink.iSpare1
+
+_LIT(KDollarLock,"$LOCK");
+_LIT(KDllDollarLock,"DLL$LOCK");
+_LIT(KLitMain,"Main");
+_LIT(KLitKill,"Kill");
+_LIT(KLitTerminate,"Terminate");
+
+/********************************************
+ * Process
+ ********************************************/
+DProcess::DProcess()
+	: iPriority(EProcPriorityForeground),
+	  iExitType((TUint8)EExitPending), iGeneration(1), iFlags(KProcessFlagJustInTime),
+	  iDynamicCode(8, _FOFF(SCodeSegEntry, iSeg), 2*256)
+	{
+	//reserve slot 0 for later use for the command line
+	iEnvironmentData[0] = EBinaryData;
+	}
+
+DProcess::~DProcess()
+	{
+	delete iCommandLine;
+	//delete any process parameters given to this process when it was created
+	TInt i;
+	for (i = 0; i < KArgIndex; ++i)
+		{
+		//if the value is a pointer to a buffer, delete it
+		//if its a pointer to an object, close it
+		TInt data = iEnvironmentData[i]&~3;
+
+		if (iEnvironmentData[i] & EBinaryData)
+			{
+			delete (HBuf8*)(data);
+			}
+		else if (iEnvironmentData[i] & EHandle)
+			{
+			((DObject*)data)->Close(NULL);
+			}
+		}
+
+	}
+
+void DProcess::Destruct()
+	{
+	}
+
+void DProcess::DoAppendName(TDes& aName)
+	{
+	DObject::DoAppendName(aName);
+	aName.Append('[');
+	aName.AppendNumFixedWidth(iUids.iUid[2].iUid,EHex,8);
+	aName.Append(']');
+	aName.AppendNumFixedWidth(iGeneration,EDecimal,4);
+	}
+
+TInt NextGeneration(const TDesC& aName, TUid aUid)
+//
+// Return the next generation number for the process
+//
+	{
+
+	const TInt KNameSuffixLen = 14;  // Number of chars after root name, see DoAppendName
+
+	__KTRACE_OPT(KPROC,Kern::Printf("DProcess::NextGeneration %S 0x%08x", &aName, aUid.iUid));
+	TInt gen=0;
+	DObjectCon& processes=*K::Containers[EProcess];
+	TKName name;
+	processes.Wait();
+	for (TInt i = 0 ; i < processes.Count() ; ++i)
+		{
+		DProcess* pP=(DProcess*)processes[i];
+		if (pP->iAccessCount > 0 && aUid.iUid == pP->iUids.iUid[2].iUid && pP->NameBuf())
+			{
+			pP->Name(name);
+			if (name.Length() > KNameSuffixLen)
+				{
+				TPtrC rootName = name.Left(name.Length() - KNameSuffixLen);
+				if (aName.CompareF(rootName) == 0 && pP->iAccessCount > 0)
+					{
+					if (pP->iGeneration>gen)
+						gen=pP->iGeneration;
+					}
+				}
+			}
+		}
+	processes.Signal();
+	__KTRACE_OPT(KPROC,Kern::Printf("DProcess generation %d",gen+1));
+	return(gen+1);
+	}
+
+__ASSERT_COMPILE(ECapability_Limit<=32);  // Kernel's iCaps caps below assumes this
+
+
+TInt DProcess::SetPaging(const TProcessCreateInfo& aInfo)
+	{// Default implementation that only verifies flags, this virtual method 
+	// is overridden in memory models that support paging.
+	if (aInfo.iFlags & TProcessCreateInfo::EDataPagingMask == 
+		TProcessCreateInfo::EDataPagingMask)
+		{
+		return KErrCorrupt;	
+		}
+	return KErrNone;
+	}
+
+
+TInt DProcess::Create(TBool aKernelProcess, TProcessCreateInfo& aInfo, HBuf* aCommandLine)
+	{
+	__KTRACE_OPT(KBOOT,Kern::Printf("DProcess::Create"));
+
+	TInt r=KErrNone;
+	iCommandLine=aCommandLine;	// do this first to prevent memory leak if error occurs
+	TPtrC f=aInfo.iFileName.Mid(aInfo.iRootNameOffset,aInfo.iRootNameLength);
+	r=SetName(&f);
+	if (r!=KErrNone)
+		return r;
+
+	// Verify and save any data paging attributes.
+	SetPaging(aInfo);
+
+	iUids=aInfo.iUids;
+	iS=aInfo.iS;
+	iDebugAttributes = (TUint8)aInfo.iDebugAttributes;
+	if (!aKernelProcess)
+		{
+		iPriority=0;
+		TInt p=ConvertPriority(aInfo.iPriority);
+		if (p<0)
+			return KErrArgument;
+		iPriority=p;
+		iGeneration=NextGeneration(f,iUids.iUid[2]);
+		}
+	else
+		{
+		iPriority = EProcPrioritySystemServer3;
+		iFlags |= KProcessFlagSystemPermanent|KProcessFlagSystemCritical;
+		}
+#ifdef BTRACE_THREAD_PRIORITY
+	BTrace8(BTrace::EThreadPriority,BTrace::EProcessPriority,this,iPriority);
+#endif
+	iId = K::NewId();
+	iCreatorId = iId;  // Initialise as self for safety because creator has special capabilities
+	if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecProcessIsolation)
+		{
+		if(aInfo.iSecurityZone==KSecurityZoneUnique)
+			iSecurityZone=iId;
+		else
+			iSecurityZone=aInfo.iSecurityZone;
+		}
+	else
+		iSecurityZone=KSecurityZoneLegacyCode;
+
+	r=K::MutexCreate((DMutex*&)iProcessLock, KDollarLock, this, EFalse, KMutexOrdProcessLock);
+	__KTRACE_OPT(KPROC,Kern::Printf("Lock mutex created, %d",r));
+	if (r!=KErrNone)
+		return r;
+	if (!aKernelProcess)
+		{
+		r=K::MutexCreate((DMutex*&)iDllLock, KDllDollarLock, this, EFalse, KMutexOrdUser);
+		if (r!=KErrNone)
+			return r;
+		}
+	r=DoCreate(aKernelProcess,aInfo);
+	if (r!=KErrNone)
+		return r;
+	__KTRACE_OPT(KPROC,Kern::Printf("Process attributes %08x",iAttributes));
+	iAttributes |= EBeingLoaded;
+
+#ifdef __DEBUGGER_SUPPORT__
+	// Send new process notification.  Note that the creator thread can not always 
+	// be figured out.  It could have been killed atfer requesting the loader to
+	// create the process or the process could be created by a kernel thread.
+	NKern::LockSystem();
+
+	DThread* creator = (DThread*)TheCurrentThread->ObjectFromHandle(aInfo.iClientHandle,EThread);
+
+	if (creator && (creator->Open() != KErrNone))
+		creator = NULL;
+
+	NKern::UnlockSystem();
+
+	__DEBUG_EVENT2(EEventAddProcess, this, creator);
+
+	if (creator)
+		creator->Close(NULL);
+#endif
+
+#ifdef BTRACE_THREAD_IDENTIFICATION
+	BTrace4(BTrace::EThreadIdentification,BTrace::EProcessCreate,this);
+#endif
+
+	iTempCodeSeg=(DCodeSeg*)aInfo.iHandle;
+	if (iTempCodeSeg)
+		{
+		if (iTempCodeSeg->iExeCodeSeg!=iTempCodeSeg)
+			return KErrNotSupported;
+		iTempCodeSeg->WaitCheckedOpen();
+		r=AttachExistingCodeSeg(aInfo);		// doesn't map the code in - Loaded() does this
+		if (r!=KErrNone)
+			return r;
+		}
+	else
+		{
+		iTempCodeSeg=M::NewCodeSeg(aInfo);
+		if (!iTempCodeSeg)
+			return KErrNoMemory;
+		iTempCodeSeg->iExeCodeSeg=iTempCodeSeg;
+		r=iTempCodeSeg->Create(aInfo,this);
+		if (r!=KErrNone)
+			return r;
+		iTempCodeSeg->WaitCheckedOpen();
+		aInfo.iHandle=iTempCodeSeg;
+		}
+	if (!aKernelProcess)
+		{
+		DThread* pT=NULL;
+		SStdEpocThreadCreateInfo t;
+		t.iType=EThreadUser;
+		t.iFunction=(TThreadFunction)aInfo.iFileEntryPoint;	// kernel will call veneer, veneer will call this
+		t.iPtr=NULL;
+		t.iSupervisorStack=NULL;
+		t.iSupervisorStackSize=0;	// zero means use default value
+		t.iUserStack=NULL;
+		t.iUserStackSize=aInfo.iStackSize;
+		t.iInitialThreadPriority=EThrdPriorityNormal;
+		t.iName.Set(KLitMain);
+		t.iAllocator=NULL;
+		t.iHeapInitialSize=aInfo.iHeapSizeMin;
+		t.iHeapMaxSize=aInfo.iHeapSizeMax;
+		t.iTotalSize = sizeof(t);
+		r=NewThread((DThread*&)pT, t, NULL, EOwnerProcess);
+		if (r==KErrNone)
+			pT->iFlags |= KThreadFlagProcessPermanent|KThreadFlagOriginal;
+		iUserThreadsRunning=1;
+		}
+	if (r!=KErrNone)
+		return r;
+	if (!aKernelProcess)
+		r=K::AddObject(this,EProcess);
+	return r;
+	}
+
+DCodeSeg* DProcess::CodeSeg()
+	{
+	return iCodeSeg ? iCodeSeg : iTempCodeSeg;
+	}
+
+TInt DProcess::SetPriority(TProcessPriority aPriority)
+	{
+	TInt p=ConvertPriority(aPriority);
+	if (p<0)
+		return KErrArgument;
+	if (iExitType!=EExitPending)
+		return KErrDied;
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Process %O SetPriority(%d)",this,p));
+	TInt r=WaitProcessLock();
+	__KTRACE_FAIL(r,Kern::Printf("PSP: %d",r));
+	if (r!=KErrNone)
+		return KErrDied;
+#ifdef BTRACE_THREAD_PRIORITY
+	BTrace8(BTrace::EThreadPriority,BTrace::EProcessPriority,this,p);
+#endif
+	NKern::LockSystem();
+	iPriority=p;
+	SDblQueLink* pLink=iThreadQ.First();
+	while (pLink!=&iThreadQ.iA)
+		{
+		DThread* pT=_LOFF(pLink,DThread,iProcessLink);
+		pT->SetThreadPriority(pT->iThreadPriority);
+		pLink=pLink->iNext;
+		NKern::FlashSystem();
+		}
+	NKern::UnlockSystem();
+	SignalProcessLock();
+	return KErrNone;
+	}
+
+TInt DProcess::ConvertPriority(TProcessPriority aPriority)
+	{
+	TInt p=-1;
+	switch(aPriority)
+		{
+		case EPriorityLow: p=EProcPriorityLow; break;
+		case EPriorityBackground: p=EProcPriorityBackground; break;
+		case EPriorityForeground: p=EProcPriorityForeground; break;
+		case EPriorityHigh: p=EProcPriorityHigh; break;
+		case EPriorityWindowServer: p=EProcPrioritySystemServer1; break;
+		case EPriorityFileServer: p=EProcPrioritySystemServer2; break;
+		case EPriorityRealTimeServer: p=EProcPriorityRealTimeServer; break;
+		case EPrioritySupervisor: p=EProcPrioritySystemServer3; break;
+		}
+	return p;
+	}
+
+TInt DProcess::Rename(const TDesC& aName)
+	{
+	if (aName.Length()>KMaxKernelName-KMaxUidName-4)
+		return KErrBadName;
+	TKName n;
+	DObject::BaseName(n); // get current name, without UID and generation number
+	if (n.MatchF(aName)==0)
+		return KErrNone;		// new name is the same so nothing to do
+
+	iGeneration = NextGeneration(aName, iUids.iUid[2]);
+
+	__KTRACE_OPT(KTHREAD,Kern::Printf("DProcess::Rename %O to %lS",this,&aName));
+	TInt r = SetName(&aName);
+#ifdef BTRACE_THREAD_IDENTIFICATION
+	Name(n);
+	BTraceN(BTrace::EThreadIdentification,BTrace::EProcessName,0,this,n.Ptr(),n.Size());
+#endif
+
+	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateProcess, this);
+	return(r);
+	}
+
+void DProcess::Release()
+	{
+#ifdef __SMP__
+	// delete thread group
+	if (iSMPUnsafeGroup)
+		{
+		NKern::GroupDestroy(iSMPUnsafeGroup);
+		Kern::Free(iSMPUnsafeGroup);
+		}
+#endif
+
+	// delete handles with lock mutex free
+	__KTRACE_OPT(KPROC,Kern::Printf("Process %O Release()",this));
+	__KTRACE_OPT(KPROC,Kern::Printf("Deleting handles"));
+	iHandles.Close(this);
+
+	// Notify process unloading before code segs are released
+	__DEBUG_EVENT(EEventUnloadingProcess, this);
+
+	__NK_ASSERT_DEBUG(iGarbageList.IsEmpty());
+
+	if (iCodeSeg || iTempCodeSeg)
+		{
+		DCodeSeg::Wait();
+		if (iCodeSeg)
+			RemoveCodeSeg(iCodeSeg, NULL);
+		DCodeSeg* pS = (DCodeSeg*)__e32_atomic_swp_ord_ptr(&iTempCodeSeg, 0);
+		if (pS)
+			pS->CheckedClose();
+		RemoveDllData();
+		DCodeSeg::Signal();
+		}
+
+	__ASSERT_ALWAYS(iDynamicCode.Count()==0, K::Fault(K::ECodeStillMapped));
+	iDynamicCode.Close();
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Closing DLL$LOCK mutex"));
+	Kern::SafeClose((DObject*&)iDllLock,this);
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Closing owning process"));
+	Kern::SafeClose((DObject*&)iOwningProcess,NULL);
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Closing DataBssStack chunk"));
+	Kern::SafeClose((DObject*&)iDataBssStackChunk,this);
+
+	NKern::LockSystem();
+	iFinalReleaseFlag = ETrue;
+	if (iProcessLock)
+		iProcessLock->Wait();			// this will get released when the lock mutex is deleted
+	NKern::UnlockSystem();
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Calling FinalRelease()"));
+	// Call FinalRelease() with process $LOCK mutex held (if it exists)
+	// and don't ever release the mutex afterwards.
+	FinalRelease();
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Closing $LOCK mutex"));
+	Kern::SafeClose((DObject*&)iProcessLock,this);
+
+	// Notify process removal before closing process
+	__DEBUG_EVENT(EEventRemoveProcess, this);
+
+#ifdef BTRACE_THREAD_IDENTIFICATION
+	BTrace4(BTrace::EThreadIdentification,BTrace::EProcessDestroy,this);
+#endif
+
+	// Kill any processes which we created but have not resumed
+	NKern::LockSystem();	// In case we died in the middle of DProcess::Resume()
+	NKern::UnlockSystem();
+	for(;;)
+		{
+		DObjectCon& processes=*K::Containers[EProcess];
+		processes.Wait();
+		DProcess* zombie=NULL;
+		TInt c=processes.Count();
+		for (TInt i=0; i<c; i++)
+			{
+			DProcess* pP=(DProcess*)processes[i];
+			if (pP->iCreatorId==iId && pP!=this && pP->Open()==KErrNone)
+				{
+				zombie = pP;
+				break;
+				}
+			}
+		processes.Signal();
+		if(!zombie)
+			break;
+		__KTRACE_OPT(KPROC,Kern::Printf("Killing zombie process %O",zombie));
+		zombie->iCreatorId=zombie->iId;
+		zombie->Die(EExitPanic,EZombieProcessKilled,KLitKernExec());
+		zombie->Close(0);
+		}
+
+	__KTRACE_OPT(KPROC,Kern::Printf("Closing process"));
+	Close(this);
+	}
+
+TInt DProcess::WaitProcessLock()
+	{
+	TInt r=KErrGeneral;
+	NKern::LockSystem();
+	if (iProcessLock && !iFinalReleaseFlag)				// iProcessLock is deleted during process death
+		{
+		r=iProcessLock->Wait();							// mutex may be resetting just before deletion
+		__KTRACE_FAIL(r,Kern::Printf("PLW: %d",r));		// will return KErrGeneral if mutex is reset
+		}
+	NKern::UnlockSystem();
+	__KTRACE_FAIL(r,Kern::Printf("WPL: %d",r));
+	return r;
+	}
+
+TInt DProcess::SignalProcessLock()
+	{
+	TInt r=KErrDied;
+	NKern::LockSystem();
+	if (iProcessLock)
+		{
+		iProcessLock->Signal();
+		r=KErrNone;
+		}
+	else
+		NKern::UnlockSystem();
+	__KTRACE_FAIL(r,Kern::Printf("SPL: %d",r));
+	return r;
+	}
+
+TInt DProcess::Loaded(TProcessCreateInfo& aInfo)
+//
+// Confirm that the process has been loaded O.K.
+//
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("DProcess::Loaded"));
+
+	//
+	// Update our code segment and dependents
+	//
+	DCodeSeg::Wait();
+
+	TInt r = KErrNone;
+
+	if (!(iTempCodeSeg->iMark & DCodeSeg::EMarkLoaded))
+		{
+		// newly loaded code segment, not another instance of same
+		r = iTempCodeSeg->Loaded(aInfo);
+		}
+
+	if (r == KErrNone)
+		r = OpenDeps();
+
+	DCodeSeg::Signal();
+
+	if (r != KErrNone)
+		return r;
+
+	if (iCodeSeg->iAttr & ECodeSegAttSMPSafe)
+		iSMPUnsafeCount = 0;
+	else
+		{
+		iSMPUnsafeCount = 1;
+#ifdef __SMP__
+		r = UpdateSMPSafe();
+		if (r != KErrNone)
+			return r;
+#endif
+		}
+	FirstThread()->iMState=DThread::EReady;
+	SetProtection(DObject::EGlobal);
+	iAttributes &= ~EBeingLoaded;
+	iReentryPoint = iCodeSeg->iEntryPtVeneer;
+
+	// Send loaded process notification.
+	__DEBUG_EVENT(EEventLoadedProcess, this);
+
+	return KErrNone;
+	}
+
+void DProcess::Resume()
+//
+// Resume a newly created process. Idempotent. Enter and return with system locked.
+//
+	{
+	if (iAttributes&EBeingLoaded)
+		K::PanicCurrentThread(EProcessNotLoaded);
+	if (!(iAttributes&EResumed))
+		{
+		iAttributes|=EResumed;
+		iCreatorId = iId;	// Creator loses control over process once it has been resumed
+		FirstThread()->Resume();
+		}
+	}
+
+void DProcess::Die(TExitType aType, TInt aReason, const TDesC &aCategory)
+//
+// Kill a process. Enter and return with system unlocked and calling thread in critical section.
+//
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("Process %O Die: %d %d %lS",this,aType,aReason,&aCategory));
+
+	TInt r=WaitProcessLock();
+	if (r!=KErrNone)
+		return;			// process already exiting
+	NKern::LockSystem();
+	if (iAttributes&EBeingLoaded)
+		{
+		// Load failed before UserSvr::ProcessLoaded() was called.
+		// The thread is still runnable however, since UserSvr::ProcessCreate() must have succeeded.
+		// We just need to set the thread state so it can be resumed.
+		FirstThread()->iMState=DThread::EReady;
+		}
+	if (iExitType==EExitPending)
+		{
+		iExitType = (TUint8)aType;
+		iExitReason=aReason;
+		if (iExitType==EExitKill)
+			iExitCategory=KLitKill;
+		else if (iExitType==EExitTerminate)
+			iExitCategory=KLitTerminate;
+		else
+			iExitCategory=aCategory;
+
+		if (iExitType!=EExitKill && (iFlags & (KProcessFlagSystemPermanent|KProcessFlagSystemCritical)))
+			K::Fault(K::ESystemProcessPanic);
+		if (iFlags & KProcessFlagSystemPermanent)
+			K::Fault(K::EPermanentProcessExit);
+
+		// Kill all threads; when the last one exits the process will be cleaned up.
+		TBool killMe = KillAllThreads(aType, aReason, aCategory);
+		if (killMe)
+			{
+			DThread* pC=TheCurrentThread;
+			pC->iExitType=(TUint8)iExitType;
+			pC->iExitReason=iExitReason;
+			pC->iExitCategory=iExitCategory;
+			NKern::DeferredExit();
+			}
+		}
+	NKern::UnlockSystem();
+	SignalProcessLock();
+	}
+
+TBool DProcess::KillAllThreads(TExitType aType, TInt aReason, const TDesC &aCategory)
+//
+// Kill all threads in a process.  Enter and return with system locked, the process lock held and
+// calling thread in a critical section.  Returns whether the current thread needs to exit too.
+//
+	{
+	TBool killMe=EFalse;
+	DThread* pC=TheCurrentThread;
+	SDblQueLink* pLink=iThreadQ.First();
+	while (pLink!=&iThreadQ.iA)
+		{
+		DThread* pT=_LOFF(pLink,DThread,iProcessLink);
+		pLink=pLink->iNext;
+		if (pT!=pC)
+			{
+			// Need to stop the current thread being killed as a consequence of killing pT
+			pT->iFlags &= ~(KThreadFlagProcessPermanent|KThreadFlagProcessCritical);
+			pT->Die(aType, aReason, aCategory);
+			}
+		else
+			{
+			killMe=ETrue;
+			NKern::UnlockSystem();
+			}
+		NKern::LockSystem();
+		}
+	return killMe;
+	}
+
+void DProcess::AddThread(DThread &aThread)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("AddThread %O to %O",&aThread,this));
+	iThreadQ.Add(&aThread.iProcessLink);
+	}
+
+TInt DProcess::NewThread(DThread*& aThread, SThreadCreateInfo& anInfo, TInt* aHandle, TOwnerType aType)
+	{
+	__KTRACE_OPT(KTHREAD,Kern::Printf("NewThread proc %O, func %08x ptr %08x",this,anInfo.iFunction,anInfo.iPtr));
+	__KTRACE_OPT(KTHREAD,Kern::Printf("type %d name %lS pri %d",anInfo.iType,&anInfo.iName,anInfo.iInitialThreadPriority));
+	if (aHandle)
+		*aHandle=0;
+	TInt r=GetNewThread(aThread,anInfo);
+	__KTRACE_FAIL(r,Kern::Printf("GNT: %d",r));
+	DThread* pT=aThread;
+	if (r==KErrNone)
+		{
+		r=pT->Create(anInfo);
+		__KTRACE_FAIL(r,Kern::Printf("NTC: %d",r));
+		if (r==KErrNone && aHandle)
+			{
+			r=K::MakeHandleAndOpen(aType,pT,*aHandle);
+			__KTRACE_FAIL(r,Kern::Printf("NT MHO: %d",r));
+			}
+		if (r==KErrNone)
+			{
+			r=WaitProcessLock();
+			if (r==KErrNone)
+				{
+				NKern::LockSystem();
+				if (iExitType==EExitPending)
+					{
+					AddThread(*pT);
+					pT->iMState=DThread::EReady;
+					// set fully constructed flag here
+					}
+				else
+					r=KErrDied;
+				NKern::UnlockSystem();
+				SignalProcessLock();
+				__KTRACE_FAIL(r,Kern::Printf("NT ADD: %d",r));
+				}
+			else
+				r=KErrDied;
+			}
+		}
+	if (r==KErrNone)
+		{
+		if (anInfo.iType == EThreadUser)
+			{
+			pT->iUserThreadState = DThread::EUserThreadCreated;
+			__e32_atomic_tas_ord32(&iUserThreadsRunning, 1, 1, 0);
+			}	
+#ifdef BTRACE_THREAD_IDENTIFICATION
+		if(BTrace::Filter(BTrace::EThreadIdentification))
+			{
+			DObjectCon* threads=Kern::Containers()[EThread];
+			threads->Wait(); // hold mutex so traces below don't get mixed up with other thread creation traces
+			TKName nameBuf;
+			Name(nameBuf);
+			BTraceN(BTrace::EThreadIdentification,BTrace::EProcessName,&pT->iNThread,this,nameBuf.Ptr(),nameBuf.Size());
+			pT->Name(nameBuf);
+			BTraceN(BTrace::EThreadIdentification,BTrace::EThreadCreate,&pT->iNThread,this,nameBuf.Ptr(),nameBuf.Size());
+			BTrace12(BTrace::EThreadIdentification,BTrace::EThreadId,&pT->iNThread,this,pT->iId);
+			threads->Signal();
+			}
+#endif
+		__DEBUG_EVENT2(EEventAddThread, pT, TheCurrentThread);
+		}
+	else if (pT)
+		{
+		if (aHandle && *aHandle)
+			{
+			K::HandleClose(*aHandle);
+			*aHandle=0;
+			}
+		pT->Stillborn();
+		aThread=NULL;
+		}
+	__KTRACE_FAIL(r,Kern::Printf("NT: %d",r));
+	return r;
+	}
+
+void DProcess::Rendezvous(TInt aReason)
+//
+// Enter and return with system unlocked and calling thread in critical section.
+//
+	{
+	TLogon::CompleteAll(iTargetLogons, TLogon::ETargetRendezvous, aReason);
+	}
+
+TInt DProcess::Logon(TRequestStatus* aStatus, TBool aRendezvous)
+	{
+	TInt r = KErrNoMemory;
+	DThread* pC = TheCurrentThread;
+	__KTRACE_OPT(KTHREAD, Kern::Printf("Thread %O Logon to process %O, status at %08x rdv=%x",
+		     pC, this, aStatus, aRendezvous));
+
+	TLogon* pL = new TLogon;
+	if (pL)
+		{
+		TUint32 type = TLogon::ETargetProcess;
+		if (aRendezvous)
+			type |= TLogon::ERendezvous;
+		r = pL->Attach(iTargetLogons, pC, this, aStatus, type);
+		if (r != KErrNone)
+			pL->Close();
+		}
+
+	__KTRACE_OPT(KTHREAD, Kern::Printf("DProcess::Logon ret %d", r));
+	return r;
+	}
+
+void DProcess::BTracePrime(TInt aCategory)
+	{
+#ifdef BTRACE_THREAD_IDENTIFICATION
+	if(aCategory==BTrace::EThreadIdentification || aCategory==-1)
+		BTrace4(BTrace::EThreadIdentification,BTrace::EProcessCreate,this);
+#endif
+	}
+
+#ifdef __SMP__
+TInt DProcess::UpdateSMPSafe()
+	{
+	TUint32 config = TheSuperPage().KernelConfigFlags();
+	if (!(config & (EKernelConfigSMPUnsafeCompat|EKernelConfigSMPUnsafeCPU0)) || this == K::TheKernelProcess)
+		return KErrNone;
+	__KTRACE_OPT(KPROC,Kern::Printf("Process %O UpdateSMPSafe count=%d",this,iSMPUnsafeCount));
+	TInt r=WaitProcessLock();
+	(void)r;
+	__NK_ASSERT_DEBUG(r==KErrNone);
+	if ((config & EKernelConfigSMPUnsafeCompat) && !iSMPUnsafeGroup)
+		{
+		SNThreadGroupCreateInfo info;
+		info.iCpuAffinity = KCpuAffinityAny;
+		iSMPUnsafeGroup = (NThreadGroup*)Kern::Alloc(sizeof(NThreadGroup));
+		r = KErrNoMemory;
+		if (iSMPUnsafeGroup)
+			r = NKern::GroupCreate(iSMPUnsafeGroup, info);
+		}
+	if (r==KErrNone)
+		{
+		SDblQueLink* pLink=iThreadQ.First();
+		while (pLink!=&iThreadQ.iA)
+			{
+			DThread* pT=_LOFF(pLink,DThread,iProcessLink);
+			NKern::QueueUserModeCallback(&pT->iNThread, &pT->iSMPSafeCallback);
+			pLink=pLink->iNext;
+			}
+		}
+	SignalProcessLock();
+	return r;
+	}
+#endif
+