kernel/eka/euser/us_func.cpp
changeset 300 1d28c8722707
parent 293 0659d0e1a03c
--- a/kernel/eka/euser/us_func.cpp	Wed Oct 20 13:58:28 2010 +0100
+++ b/kernel/eka/euser/us_func.cpp	Tue Nov 02 15:29:23 2010 +0000
@@ -744,26 +744,96 @@
 
 
 
+TBool TEntryPointList::AlreadyCalled(TLinAddr aEP)
+	{
+	TInt i;
+
+	// if we find it in the list before the current one
+	// then it was already called, return true
+	for (i=0; i<iCurrentEP; ++i)
+		if (iEPs[i] == aEP)
+			return ETrue;
+
+	// if it *is* the current one (i==iCurrentEP here)
+	// then we're in some kind of hideous cycle. There is no
+	// way to resolve this that isn't wrong, but some people
+	// may depend on it anyway. The safest thing to do is to
+	// just claim the EP is already called and hope that
+	// the constructors aren't actually dependent on each other.
+	if (iEPs[i] == aEP)
+		return ETrue;
+		
+	// if we find it *after* the current one then it's not
+	// already been called, but we need to call it now
+	// rather than when we get that far back up the stack,
+	// so set that copy to -1.
+	for (++i; i<iNumEPs; ++i)
+		if (iEPs[i] == aEP)
+			iEPs[i] = 0xFFFFFFFFU;
+
+	// if this is not the top of the stack recurse, otherwise
+	// return false so the current load will call it
+	if (iPrevList)
+		return iPrevList->AlreadyCalled(aEP);
+	else
+		return EFalse;
+	}
+
+
+TInt TEntryPointList::CallEPs()
+	{
+	// The TLS entry for KNestedEntryPointCallKey is the head
+	// of a linked list of TEntryPointList objects. Add this one
+	// to the front of the list. iPrevList will end up NULL if
+	// there is no nested load yet.
+	// Only one thread per process can be doing a load at a time
+	// because of the DLL lock, so using TLS for this is fine.
+	iPrevList=(TEntryPointList*)UserSvr::DllTls(KNestedEntryPointCallKey, KDllUid_Special);
+	TInt r=UserSvr::DllSetTls(KNestedEntryPointCallKey, KDllUid_Special, this);
+	if (r != KErrNone)
+		return r;
+
+	// call each entry point unless it's already been called higher
+	// in the nested loading process, or it's been set to -1 because
+	// it was called lower in the nested load.
+	for (iCurrentEP=0; iCurrentEP<iNumEPs; ++iCurrentEP)
+		{
+		TLinAddr ep=iEPs[iCurrentEP];
+		if (ep != 0xFFFFFFFFU && (!iPrevList || !iPrevList->AlreadyCalled(ep)))
+			{
+			TLibraryEntry f=(TLibraryEntry)ep;
+			r = (*f)(KModuleEntryReasonProcessAttach);
+			if (r != KErrNone)
+				break;
+			}
+		}
+
+	// Take this object off the list before returning
+	UserSvr::DllSetTls(KNestedEntryPointCallKey, KDllUid_Special, iPrevList);
+
+	return r;
+	}
+
+
+
+
 void CallStaticEntryPoints(TBool aInit)
 	{
-	TLinAddr ep[KMaxLibraryEntryPoints];
-	TInt numEps=KMaxLibraryEntryPoints;
-	TInt r=E32Loader::StaticCallList(numEps, ep);
+	TEntryPointList eplist;
+	eplist.iNumEPs=KMaxLibraryEntryPoints;
+	TInt r=E32Loader::StaticCallList(eplist.iNumEPs, eplist.iEPs);
 	if (r!=KErrNone)
 		return;
+	eplist.iNumEPs -= 1; // last EP is always process entry point
 	if (aInit)
 		{
-		for (TInt i=0; i<numEps-1; ++i)	// last EP is always process entry point
-			{
-			TLibraryEntry f=(TLibraryEntry)ep[i];
-			(*f)(KModuleEntryReasonProcessAttach);
-			}
+		eplist.CallEPs();
 		}
 	else
 		{
-		for (TInt i=numEps-2; i>=0; --i)	// last EP is always process entry point
+		for (TInt i=eplist.iNumEPs-1; i>=0; --i)
 			{
-			TLibraryEntry f=(TLibraryEntry)ep[i];
+			TLibraryEntry f=(TLibraryEntry)eplist.iEPs[i];
 			(*f)(KModuleEntryReasonProcessDetach);
 			}
 		}
@@ -778,6 +848,7 @@
 */
 	{
 	CallStaticEntryPoints(ETrue);
+	E32Loader::StaticCallsDone();
 	}
 
 
@@ -2017,13 +2088,6 @@
 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
 	};
 
-/* RVCT 3.1 and 4.0 read past the end of arrays when unrolling loops.
- * This only happens when using -O3 -Otime, so force to -O2.
- */
-#if __ARMCC_VERSION >= 310000 
-#pragma push
-#pragma O2
-#endif
 
 /**
 Performs a CCITT CRC-32 checksum on the specified data.
@@ -2044,6 +2108,3 @@
 		crc = (crc >> 8) ^ CrcTab32[(crc ^ *p++) & 0xff];
 	aCrc = crc;
 	}
-#if __ARMCC_VERSION >= 310000 
-#pragma pop
-#endif