medblock.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:12k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "medblock.h"
  36. #include "hlxclib/string.h"
  37. CMediumBlockAllocator::CMediumBlockAllocator()
  38.     :   m_nMinBucketSize(400)
  39.     , m_nNumberBuckets(256)
  40.     , m_nBucketSize(128)
  41.     , m_ppBuckets(0)
  42.     , m_pTimeStampArray(0)
  43.     , m_pCountArray(0)
  44.     , m_nLastTimeStamp(0)
  45.     , m_nCurrentTimeStamp(0)
  46.     , m_nLastMinimizeTime(0)
  47.     , m_nHeaderSize(0)
  48.     , m_nRelaxTime(5000)
  49.     , m_nCallbackTime(500)
  50.     , m_nGarbageTime(10000)
  51.     , m_nGarbageDivider(10)
  52.     , m_lRefCount(0)
  53.     , m_nLastRelaxTime(0)
  54.     , m_hCallback(0)
  55.     , m_pScheduler(0)
  56.     , m_pMutex(NULL)
  57. {
  58. #ifdef THREADS_SUPPORTED
  59.     HXMutex::MakeMutex(m_pMutex);
  60. #else
  61.     HXMutex::MakeStubMutex(m_pMutex);
  62. #endif
  63.     m_hCallback = 0;
  64.     m_ppBuckets = new CMemoryNode*[m_nNumberBuckets];
  65.     m_pTimeStampArray = new UINT32[m_nNumberBuckets];
  66.     m_pTimeStampArray = new UINT32[m_nNumberBuckets];
  67.     m_pCountArray = new UINT32[m_nNumberBuckets];
  68.     if (m_ppBuckets)
  69.     {
  70. for(int i = 0; i< (int)m_nNumberBuckets; i++)
  71. {
  72.     m_ppBuckets[i] = 0;
  73.     m_pCountArray[i] = 0;
  74. }
  75.     }
  76.     
  77.     m_nCurrentTimeStamp = HX_GET_TICKCOUNT();
  78.     m_nLastRelaxTime = m_nCurrentTimeStamp;
  79.     m_nLastMinimizeTime = m_nCurrentTimeStamp;
  80.     // round to the nearest dword size. 
  81.     // I think this is the correct alignment for all platforms.
  82.     m_nHeaderSize = (sizeof(CMemoryNode) + sizeof(double) - 1) & ~(sizeof(double) - 1);
  83. }
  84. CMediumBlockAllocator::~CMediumBlockAllocator()
  85. {
  86.     HX_RELEASE(m_pScheduler);
  87.     HeapMinimize();
  88.     HX_VECTOR_DELETE(m_ppBuckets);
  89.     HX_VECTOR_DELETE(m_pTimeStampArray);
  90.     HX_VECTOR_DELETE(m_pCountArray);
  91.     HX_DELETE(m_pMutex);
  92. }
  93. void CMediumBlockAllocator::SetScheduler(IUnknown* pUnk)
  94. {
  95.     if (m_pScheduler && m_hCallback)
  96.     {
  97. m_pScheduler->Remove(m_hCallback);
  98. m_hCallback = 0;
  99.     }
  100.     HX_RELEASE(m_pScheduler);
  101.     if (pUnk)
  102.     {
  103. pUnk->QueryInterface(IID_IHXScheduler, (void**)&m_pScheduler);
  104. if (m_pScheduler)
  105. {
  106.     m_hCallback = m_pScheduler->RelativeEnter((IHXCallback*)this, m_nCallbackTime);
  107. }
  108.     }
  109. }
  110. /****************************************************************************
  111. * Method:
  112. * IUnknown::QueryInterface
  113. * Purpose:
  114. * Implement this to export the interfaces supported by your 
  115. * object.
  116. *
  117. ****************************************************************************/
  118. STDMETHODIMP CMediumBlockAllocator::QueryInterface(REFIID riid, void** ppvObj)
  119. {
  120.     QInterfaceList qiList[] =
  121.         {
  122.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IMalloc*)this },
  123.             { GET_IIDHANDLE(IID_IMalloc), (IMalloc*)this },
  124.             { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this },
  125.         };
  126.     
  127.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  128. }
  129. /****************************************************************************
  130. * Method:
  131. * IUnknown::AddRef
  132. * Purpose:
  133. * Everyone usually implements this the same... feel free to use
  134. * this implementation.
  135. *
  136. ****************************************************************************/
  137. STDMETHODIMP_(ULONG32) CMediumBlockAllocator::AddRef()
  138. {
  139.     return InterlockedIncrement(&m_lRefCount);
  140. }
  141. /****************************************************************************
  142. * Method:
  143. * IUnknown::Release
  144. * Purpose:
  145. * Everyone usually implements this the same... feel free to use
  146. * this implementation.
  147. *
  148. ****************************************************************************/
  149. STDMETHODIMP_(ULONG32) CMediumBlockAllocator::Release()
  150. {
  151.     if (InterlockedDecrement(&m_lRefCount) > 0)
  152.     {
  153. return m_lRefCount;
  154.     }
  155.     delete this;
  156.     return 0;
  157. }
  158. /****************************************************************************
  159. * Method:
  160. * IMalloc::Alloc
  161. * Purpose:
  162. * If there is a block of memory within the current pools
  163. * to satistify then it will be given, if there is no such 
  164. * object then we will ask the default memory allocator for 
  165. * it. 
  166. *
  167. ****************************************************************************/
  168. STDMETHODIMP_(void*) CMediumBlockAllocator::Alloc(UINT32 ulLength)
  169. {
  170.     m_pMutex->Lock();
  171.     void*     returnValue = NULL;
  172.     CMemoryNode*    pMemNode = NULL;
  173.     // figure out what bucket this belongs in
  174.     UINT32 bucketIndex = ulLength/m_nBucketSize;
  175.     if (ulLength> m_nMinBucketSize && bucketIndex < m_nNumberBuckets)
  176.     {
  177. if (m_ppBuckets[bucketIndex])
  178. {
  179.     pMemNode = m_ppBuckets[bucketIndex];
  180.     m_ppBuckets[bucketIndex] = pMemNode->m_pNext;
  181.     m_pCountArray[bucketIndex] = m_pCountArray[bucketIndex] -1;
  182.     m_pTimeStampArray[bucketIndex] = m_nCurrentTimeStamp;
  183.     returnValue = (void*) (((char*) (pMemNode)) + m_nHeaderSize);
  184. }
  185. if (!returnValue)
  186. {
  187.     pMemNode = (CMemoryNode*) new UCHAR[((bucketIndex+1)*m_nBucketSize + m_nHeaderSize - 1)];
  188.     if (pMemNode)
  189.     {
  190. pMemNode->m_nSize = (bucketIndex+1)* m_nBucketSize - 1;
  191. pMemNode->m_pNext = NULL;
  192. returnValue = (void*) ((char*)pMemNode + m_nHeaderSize);
  193.     }
  194. }
  195.     }
  196.     else
  197.     {
  198. pMemNode = (CMemoryNode*) new UCHAR[(ulLength+ m_nHeaderSize)];
  199. if (pMemNode)
  200. {
  201.     pMemNode->m_nSize = ulLength;
  202.     pMemNode->m_pNext = NULL;
  203.     returnValue = (void*) ((char*)pMemNode + m_nHeaderSize);
  204. }
  205.     }
  206.     m_pMutex->Unlock();
  207.     return returnValue;
  208. }
  209. /****************************************************************************
  210. * Method:
  211. * IMalloc::Free
  212. * Purpose:
  213. * Returns a given block of memory to the memory buckets 
  214. *
  215. ****************************************************************************/
  216. STDMETHODIMP_(void) CMediumBlockAllocator::Free(void* pMem)
  217. {
  218.     m_pMutex->Lock();
  219.     CMemoryNode* pMemNode   = (CMemoryNode*) (((char*)pMem) - m_nHeaderSize);
  220.     UINT32 bucketIndex = (pMemNode->m_nSize)/m_nBucketSize;
  221.     if (pMemNode->m_nSize > m_nMinBucketSize && bucketIndex < m_nNumberBuckets)
  222.     {
  223. m_pTimeStampArray[bucketIndex] = m_nCurrentTimeStamp;
  224. CMemoryNode* pBufferHead = m_ppBuckets[bucketIndex];
  225. m_pCountArray[bucketIndex] = m_pCountArray[bucketIndex]+1;
  226. if (pBufferHead)
  227. {
  228.     m_ppBuckets[bucketIndex] = pMemNode;
  229.     pMemNode->m_pNext = pBufferHead;
  230. }
  231. else
  232. {
  233.     m_ppBuckets[bucketIndex] = pMemNode;
  234.     pMemNode->m_pNext = NULL;
  235. }
  236.     }
  237.     else
  238.     {
  239. HX_DELETE(pMemNode);
  240.     }
  241.     m_pMutex->Unlock();
  242. }
  243. /****************************************************************************
  244. * Method:
  245. * IMalloc::Realloc
  246. * Purpose:
  247. * Incrediably stupid. Creates a new block and memcopies it.
  248. *
  249. ****************************************************************************/
  250. STDMETHODIMP_(void*) CMediumBlockAllocator::Realloc(void* pMem, UINT32 count)
  251. {
  252.     m_pMutex->Lock();
  253.     CMemoryNode* pMemNode   = (CMemoryNode*) ((char*)pMem - sizeof(CMemoryNode));
  254.     void* pNewMemory = Alloc(count);
  255.     if (pNewMemory)
  256.     {
  257. memcpy(pNewMemory, pMem, pMemNode->m_nSize); /* Flawfinder: ignore */
  258. Free(pMem);
  259.     }
  260.     m_pMutex->Unlock();
  261.     return pNewMemory;
  262. }
  263. /****************************************************************************
  264. * Method:
  265. * IMalloc::GetSize
  266. * Purpose:
  267. * Simply returns the size requested when the block was allocated.
  268. *
  269. ****************************************************************************/
  270. STDMETHODIMP_(UINT32) CMediumBlockAllocator::GetSize(void* pMem)
  271. {
  272.     CMemoryNode* pMemNode   = (CMemoryNode*) ((char*)pMem - m_nHeaderSize);
  273.     return pMemNode->m_nSize;
  274. }
  275. /****************************************************************************
  276. * Method:
  277. * IMalloc::DidAlloc
  278. * Purpose:
  279. * Have not thought of a nice way to do this.
  280. *
  281. ****************************************************************************/
  282. STDMETHODIMP_(BOOL) CMediumBlockAllocator::DidAlloc(void* pMem)
  283. {
  284.     return FALSE;
  285. }
  286. /****************************************************************************
  287. * Method:
  288. * IMalloc::HeapMinimize
  289. * Purpose:
  290. * Deletes all blocks within the free list.
  291. *
  292. ****************************************************************************/
  293. STDMETHODIMP_(void) CMediumBlockAllocator::HeapMinimize()
  294. {
  295.     m_pMutex->Lock();
  296.     CMemoryNode* pNode;
  297.     CMemoryNode* pTempNode;
  298.     for(UINT32 i = 0; i<m_nNumberBuckets; i++)
  299.     {
  300. pNode = m_ppBuckets[i];
  301. m_pCountArray[i] = 0;
  302. m_pTimeStampArray = 0;
  303. while (pNode)
  304. {
  305.     pTempNode = pNode;
  306.     pNode = pTempNode->m_pNext;
  307.     HX_DELETE(pTempNode);
  308. }
  309. m_ppBuckets[i] = NULL;
  310.     }
  311.     m_pMutex->Unlock();
  312. }
  313. /****************************************************************************
  314. * Method:
  315. * IHXCallback::Func
  316. * Purpose:
  317. * Resets the m_nCurrentTimeStamp to the granularity of 
  318. * m_nCallbackTime so we needn't call gettimeofday() all of the 
  319. * time. Also attempts to reduce the size of the free lists
  320. * if a certian tolerance has been exceeded.
  321. *
  322. ****************************************************************************/
  323. STDMETHODIMP
  324. CMediumBlockAllocator::Func()
  325. {
  326.     // every time through this function we must reset the current timestamp
  327.     m_nCurrentTimeStamp = HX_GET_TICKCOUNT();
  328.     // now if the current 
  329.     if (CALCULATE_ELAPSED_TICKS(m_nLastRelaxTime, m_nCurrentTimeStamp) > m_nRelaxTime)
  330.     {
  331. m_nLastRelaxTime = m_nCurrentTimeStamp;
  332. RelaxBuckets();
  333.     }
  334.     
  335.     m_hCallback = m_pScheduler->RelativeEnter((IHXCallback*)this, m_nCallbackTime);
  336.     return HXR_OK;
  337. }
  338. /****************************************************************************
  339. * Method:
  340. * CMediumBlockAllocator::Func
  341. * Purpose:
  342. * Helper function called by Func. Attempts to slowly reduce 
  343. * the size of the buckets if no one has used them in a while.
  344. *
  345. ****************************************************************************/
  346. void CMediumBlockAllocator::RelaxBuckets()
  347. {
  348.     // go through the heap look for places that have a list of nodes
  349.     // if the time stamp on that node is greater than relax time then 
  350.     // throw away a few items off of that head. 
  351.     m_pMutex->Lock();
  352.     for(UINT32 i = 0; i<m_nNumberBuckets; i++)
  353.     {
  354. CMemoryNode*  pListItem = m_ppBuckets[i];
  355. if (pListItem)
  356. {
  357.     if (CALCULATE_ELAPSED_TICKS(m_pTimeStampArray[i], m_nCurrentTimeStamp) > m_nGarbageTime)
  358.     {
  359. // find out how many nodes we have
  360. UINT32 nNodesToThrowAway = m_pCountArray[i]/m_nGarbageDivider;
  361. if (!nNodesToThrowAway)
  362. {
  363.     nNodesToThrowAway = 1;
  364. }
  365. m_pCountArray[i] -= nNodesToThrowAway;
  366. for (;nNodesToThrowAway; nNodesToThrowAway--)
  367. {
  368.     m_ppBuckets[i] = pListItem->m_pNext;
  369.     HX_DELETE(pListItem);
  370.     pListItem = m_ppBuckets[i];
  371. }
  372.     }
  373. }
  374.     }
  375.     m_pMutex->Unlock();
  376. }