windowing/windowserver/nga/SERVER/WsMemMgr.cpp
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 2007-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 "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 //
       
    15 
       
    16 #include "WsMemMgr.h"
       
    17 #include "inifile.h"
       
    18 #include "panics.h"
       
    19 #include "wstop.h"
       
    20 
       
    21 static const TTimeIntervalMicroSeconds KBurstDuration = 1000000; //one second
       
    22 static const TInt KMaxMemoryReleasesPerBurst = 5;
       
    23 CWsMemoryManager * CWsMemoryManager::iStatic = NULL;
       
    24 
       
    25 CWsMemoryManager * CWsMemoryManager::Static()
       
    26 	{
       
    27 	return iStatic;
       
    28 	}
       
    29 
       
    30 CWsMemoryManager * CWsMemoryManager::NewLC()
       
    31 	{
       
    32 	CWsMemoryManager * self = new (ELeave) CWsMemoryManager;
       
    33 	CleanupStack::PushL(self);
       
    34 	self->ConstructL();
       
    35 	iStatic = self;
       
    36 	return iStatic;
       
    37 	}
       
    38 
       
    39 CWsMemoryManager::CWsMemoryManager()
       
    40 	{
       
    41 	iImpl = User::SwitchAllocator(this);
       
    42 	}
       
    43 	
       
    44 CWsMemoryManager::~CWsMemoryManager()
       
    45 	{
       
    46 	WS_ASSERT_ALWAYS(this == User::SwitchAllocator(iImpl),EWsPanicMemoryManager);
       
    47 	iStatic = 0;
       
    48 	if (iReserve!=NULL)
       
    49 		{
       
    50 		Free(iReserve);
       
    51 		}
       
    52 	}
       
    53 
       
    54 void CWsMemoryManager::ConstructL()
       
    55 	{
       
    56 	_LIT(KMemMgrReserve, "MEMORYRESERVE");
       
    57 	const TInt KDefaultMemMgrReserve = 1024;
       
    58 	
       
    59 	if (!WsIniFile->FindVar(KMemMgrReserve, iReserveSize))
       
    60 		iReserveSize = KDefaultMemMgrReserve;
       
    61 
       
    62 	if (iReserveSize > 0)
       
    63 		iReserve = Alloc(iReserveSize);
       
    64 	
       
    65 	iCurrentBurstStart.UniversalTime();
       
    66 	}
       
    67 
       
    68 /**
       
    69 Tells the memory manager to fail on next retry.
       
    70 I.e. whenever the next allocation failure occurs, the memory manager won't try 
       
    71 to free up memory to have another go at the allocation.
       
    72 
       
    73 N.B. this only applies for the next failure, the state is reset when there is an
       
    74 allocation failure.
       
    75 
       
    76 This method is only to be used for OOM testing.
       
    77 */
       
    78 void CWsMemoryManager::SetFailNextRetry()
       
    79 	{
       
    80 	iFailNextRetry = ETrue;
       
    81 	}
       
    82 
       
    83 /**
       
    84 Implementing RAllocator
       
    85 */
       
    86 
       
    87 /**
       
    88 Alloc and ReAlloc attempt to obtain memory through CWsTop::ReleaseMemory when they run low.
       
    89 ReleaseMemory looks for blocks of memory that the window server doesn't need urgently and frees
       
    90 them.
       
    91 */
       
    92 TAny* CWsMemoryManager::Alloc(TInt aSize)
       
    93 	{
       
    94 	TBool keepTrying = ETrue;
       
    95 	do
       
    96 		{
       
    97 		if(iReleasing)
       
    98 			return iImpl->Alloc(aSize); //fallback on RAllocator
       
    99 		
       
   100 		if(TAny* ret = iImpl->Alloc(aSize)) //normal case
       
   101 			return ret;
       
   102 		
       
   103 		TTime now;
       
   104 		now.UniversalTime();
       
   105 		if(now.MicroSecondsFrom(iCurrentBurstStart) < KBurstDuration)
       
   106 			{
       
   107 			iCurrentBurstReleaseCount++;
       
   108 			if(iCurrentBurstReleaseCount > KMaxMemoryReleasesPerBurst)
       
   109 				return NULL;
       
   110 			}
       
   111 		else
       
   112 			{
       
   113 			iCurrentBurstStart = now;
       
   114 			iCurrentBurstReleaseCount = 1;
       
   115 			}
       
   116 		
       
   117 		if(iReserveEnabled && iReserve && (aSize < iReserveSize))
       
   118 			{
       
   119 			Free(iReserve);
       
   120 			iReserve = NULL;
       
   121 			}
       
   122 		else
       
   123 			{
       
   124 			iReleasing = ETrue;
       
   125 			keepTrying = CWsTop::ReleaseMemory();
       
   126 			if(keepTrying)
       
   127  				{
       
   128  				const TInt reclaimed = Compress(); //Try to give back to the OS
       
   129  				}
       
   130 			iReleasing = EFalse;
       
   131 			}
       
   132 		
       
   133 		//used for OOM testing only
       
   134 		if(iFailNextRetry)
       
   135 			{
       
   136 			iFailNextRetry = EFalse;
       
   137 			keepTrying = EFalse;
       
   138 			}
       
   139 		
       
   140 		} while(keepTrying);
       
   141 
       
   142 	return NULL;
       
   143 	}
       
   144 
       
   145 TAny* CWsMemoryManager::ReAlloc(TAny* aPtr, TInt aSize, TInt aMode)
       
   146 	{
       
   147 	TBool keepTrying = ETrue;
       
   148 	do
       
   149 		{
       
   150 		if(iReleasing)
       
   151 			return iImpl->ReAlloc(aPtr, aSize, aMode); //fallback on RAllocator
       
   152 		
       
   153 		if(TAny* ret = iImpl->ReAlloc(aPtr, aSize, aMode)) //normal case
       
   154 			return ret;
       
   155 			
       
   156 		TTime now;
       
   157 		now.UniversalTime();
       
   158 		if(now.MicroSecondsFrom(iCurrentBurstStart) < KBurstDuration)
       
   159 			{
       
   160 			iCurrentBurstReleaseCount++;
       
   161 			if(iCurrentBurstReleaseCount > KMaxMemoryReleasesPerBurst)
       
   162 				return NULL;
       
   163 			}
       
   164 		else
       
   165 			{
       
   166 			iCurrentBurstStart = now;
       
   167 			iCurrentBurstReleaseCount = 1;
       
   168 			}
       
   169 			
       
   170 		if(iReserveEnabled && iReserve && (aSize < iReserveSize))
       
   171 			{
       
   172 			Free(iReserve);
       
   173 			iReserve = NULL;
       
   174 			}
       
   175 		else
       
   176 			{
       
   177 			iReleasing = ETrue;
       
   178 			keepTrying = CWsTop::ReleaseMemory();
       
   179 			if(keepTrying)
       
   180  				{
       
   181  				const TInt reclaimed = Compress(); //Try to give back to the OS
       
   182  				}	
       
   183 			iReleasing = EFalse;
       
   184 			}
       
   185 			
       
   186 		//used for OOM testing only
       
   187 		if(iFailNextRetry)
       
   188 			{
       
   189 			iFailNextRetry = EFalse;
       
   190 			keepTrying = EFalse;
       
   191 			}
       
   192 
       
   193 		} while(keepTrying);
       
   194 
       
   195 	return NULL;
       
   196 	}
       
   197 
       
   198 /**
       
   199 The rest of these functions just call the default implementation
       
   200 */
       
   201 void CWsMemoryManager::Free(TAny* aPtr)
       
   202 	{
       
   203 	return iImpl->Free(aPtr);
       
   204 	}
       
   205 
       
   206 TInt CWsMemoryManager::AllocLen(const TAny* aCell) const
       
   207 	{
       
   208 	return iImpl->AllocLen(aCell);
       
   209 	}
       
   210 
       
   211 TInt CWsMemoryManager::Compress()
       
   212 	{
       
   213 	return iImpl->Compress();
       
   214 	}
       
   215 
       
   216 void CWsMemoryManager::Reset()
       
   217 	{
       
   218 	iImpl->Reset();
       
   219 	}
       
   220 
       
   221 TInt CWsMemoryManager::AllocSize(TInt& aTotalAllocSize) const
       
   222 	{
       
   223 	return iImpl->AllocSize(aTotalAllocSize);
       
   224 	}
       
   225 
       
   226 TInt CWsMemoryManager::Available(TInt& aBiggestBlock) const
       
   227 	{
       
   228 	return iImpl->Available(aBiggestBlock);
       
   229 	}
       
   230 
       
   231 TInt CWsMemoryManager::DebugFunction(TInt aFunc, TAny* a1, TAny* a2)
       
   232 	{
       
   233 	return iImpl->DebugFunction(aFunc,a1,a2);
       
   234 	}
       
   235 
       
   236 TInt CWsMemoryManager::Count() const
       
   237 	{
       
   238 	return iImpl->Count();
       
   239 	}
       
   240 /** This is a fairly dumb way to enable and disable the reserve, but we normally
       
   241 get away with it because wserv is high priority.  A better approach would be to
       
   242 use placement new into the reserve memory and manage it directly.  This would also
       
   243 allow us to track misbehaving code which allocated during OOM drawing and didn't
       
   244 free at the end.
       
   245 */
       
   246 void CWsMemoryManager::EnableReserve()
       
   247 	{
       
   248 	WS_ASSERT_DEBUG(!iReserveEnabled, EWsPanicMemoryManager);
       
   249 	iReserveEnabled = ETrue;
       
   250 	}
       
   251 
       
   252 void CWsMemoryManager::DisableReserve()
       
   253 	{
       
   254 	WS_ASSERT_DEBUG(iReserveEnabled, EWsPanicMemoryManager);
       
   255 	iReserveEnabled = EFalse;
       
   256 	if((!iReserve) && (iReserveSize > 0))
       
   257 		iReserve = Alloc(iReserveSize);
       
   258 	}