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

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. // no memory map support on VXWORKS or Symbian
  36. #if !defined(_VXWORKS) && !defined(_SYMBIAN)
  37. /*
  38.  * MMapMgr needs atomic ref increments.
  39.  */
  40. #define _WIN32_USE_INTERLOCKED_INCREMENT
  41. #include "hxcom.h"
  42. #include "hxtypes.h"
  43. #ifndef _MACINTOSH
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #ifdef _UNIX
  47. #include <unistd.h>
  48. #include <fcntl.h>
  49. #endif
  50. #include "hlxclib/sys/types.h"
  51. #include "hlxclib/sys/stat.h"
  52. #include "hlxclib/io.h"
  53. #if defined(_UNIX) && !defined(_BEOS)
  54. #include <sys/mman.h>
  55. #endif
  56. #include "hxbuffer.h"
  57. #include "hxstrutl.h"
  58. #include "hxmap.h"
  59. #include "hxengin.h"
  60. #include "mmapmgr.h"
  61. #include "hxspriv.h"
  62. #include "debug.h"
  63. #include "mmapdatf.h"
  64. #include "hxassert.h"
  65. #include "hxmon.h"
  66. #ifdef _MMM_NEED_MUTEX
  67. #include "hxcomm.h"
  68. #endif
  69. //#define  MMAPDEBUG
  70. //#define  MMAPMOREDEBUG
  71. #ifdef MMAPDEBUG
  72. #define MMAPDPRINTF(x) printf x
  73. #else
  74. #define MMAPDPRINTF(x)
  75. #endif
  76. /* Must be a multiple of the page size */
  77. #define MMAP_INITIAL_CHUNK_SIZE
  78. (256 * 1024)
  79. #define MMAP_EXTRA_SLOP_SIZE
  80. 65536
  81. #define MAX_ADDRESS_SPACE_USED
  82. 1 * 1024 * 1000 * 1000 // 1 Gig
  83. #define MS_BETWEEN_HANDLE_REAP_BUCKETS
  84. 3000
  85. #define NUMBER_OF_REAP_BUCKETS_TO_EMPTY_ON_ADDRESS_SPACE_EXHUSTED
  86. 2
  87. #ifndef MAP_FAIL
  88. #define MAP_FAIL ((void *)-1)
  89. #endif
  90. /*
  91.  * On Linux/NT we have 1 address space for all procs.  On other unicies we
  92.  * have 'n' processes and 'n' address spaces.  This variables tracks address
  93.  * usage correctly on all 3 types of OSes.
  94.  */
  95. UINT32     g_ulAddressSpaceUsed = 0;
  96. /*
  97.  *  On the server we wish to reap the memory after a little bit of time
  98.  *  because it is very likely that we will want to use it again in a 
  99.  *  short amount of time. On the client we do not wish to do this, becuase we
  100.  *  can not do good things like delete the file if it is mem-mapped.
  101.  */
  102. static BOOL z_bDeterminedIfWeAreWithinServer    = FALSE;
  103. static BOOL z_bWithinServer                     = FALSE;
  104. /*
  105.  * On NT we only have one MemoryMapManager per server.
  106.  * On other unix platforms, we have on MemoryMapManager
  107.  * per process.
  108.  *
  109.  * XXXSMP The Linux code is Sub-Optimal!!  Since we have 1 address space,
  110.  * we should take advantage of the fact that pages that we are trying to
  111.  * map in one thread may already be mapped by another thread.  With 'n'
  112.  * MMM's, we can't take advantage of this optimization.
  113.  */
  114. MemoryMapManager::MemoryMapManager(IUnknown* pContext,
  115. BOOL bDisableMemoryMappedIO, UINT32 ulChunkSize)
  116.     : m_pMMMCallback(NULL)
  117. {
  118.     m_pDevINodeToFileInfoMap = new CHXMapStringToOb;
  119.     m_pDevINodeToFileInfoMap->InitHashTable(517);
  120.     m_ulActiveReapList = 0;
  121.     HX_VERIFY (HXR_OK ==
  122. pContext->QueryInterface(IID_IHXScheduler, (void **)&m_pScheduler));
  123.     if (!z_bDeterminedIfWeAreWithinServer)
  124.     {
  125.         z_bDeterminedIfWeAreWithinServer = TRUE;
  126.         IHXRegistry* pHXReg = NULL;
  127.         pContext->QueryInterface(IID_IHXRegistry, (void **)&pHXReg);
  128.         if (pHXReg)
  129.         {
  130.             HXPropType type = pHXReg->GetTypeByName("server.version");
  131.             if (type!= PT_UNKNOWN)
  132.             {
  133.                 z_bWithinServer = TRUE;
  134.             }
  135.             HX_RELEASE(pHXReg);
  136.         }
  137.     }
  138.     if (ulChunkSize)
  139.     {
  140. m_ulChunkSize = ulChunkSize;
  141.     }
  142.     else
  143.     {
  144. m_ulChunkSize = MMAP_INITIAL_CHUNK_SIZE;
  145.     }
  146.     m_lRefCount = 0;
  147.     if (z_bWithinServer)
  148.     {
  149. m_pMMMCallback = new MMMCallback(this);
  150. if (m_pMMMCallback)
  151. {
  152.     m_pMMMCallback->AddRef();
  153.     m_pMMMCallback->m_hPendingHandle = m_pScheduler->RelativeEnter(m_pMMMCallback, MS_BETWEEN_HANDLE_REAP_BUCKETS);
  154. }
  155.     }
  156. #ifdef _MMM_NEED_MUTEX
  157.     m_pMutex = NULL;
  158. #ifdef _DEBUG
  159.     m_bHaveMutex = FALSE;
  160. #endif
  161.     IHXCommonClassFactory* pCCF;
  162.     if (HXR_OK == pContext->QueryInterface(IID_IHXCommonClassFactory,
  163. (void**)&pCCF))
  164.     {
  165. pCCF->CreateInstance(CLSID_IHXMutex, (void**)&m_pMutex);
  166. pCCF->Release();
  167.     }
  168. #endif
  169.     m_pFastAlloc = NULL;
  170.     pContext->QueryInterface(IID_IHXFastAlloc, (void **)&m_pFastAlloc);
  171.     m_bDisableMemoryMappedIO = bDisableMemoryMappedIO;
  172. }
  173. MemoryMapManager::~MemoryMapManager()
  174. {
  175.     /* This had better be empty by now!! */
  176.     HX_DELETE(m_pDevINodeToFileInfoMap);
  177.     if (m_pMMMCallback && m_pMMMCallback->m_hPendingHandle)
  178.     {
  179. m_pScheduler->Remove(m_pMMMCallback->m_hPendingHandle);
  180.     }
  181.     HX_RELEASE(m_pMMMCallback);
  182.     HX_RELEASE(m_pScheduler);
  183.     HX_RELEASE(m_pFastAlloc);
  184. #ifdef _MMM_NEED_MUTEX
  185.     HX_RELEASE(m_pMutex);
  186. #endif
  187. }
  188. STDMETHODIMP
  189. MemoryMapManager::QueryInterface(REFIID riid, void** ppvObj)
  190. {
  191.     if (IsEqualIID(riid, IID_IUnknown))
  192.     {
  193.         AddRef();
  194.         *ppvObj = (IUnknown*)(IUnknown*)this;
  195.         return HXR_OK;
  196.     }
  197.     *ppvObj = NULL;
  198.     return HXR_NOINTERFACE;
  199. }
  200. /*
  201.  * These are the only AddRef/Release pairs
  202.  * that need to be thread safe.  All the
  203.  * other don't need to be.  Since _WIN32_USE_INTERLOCKED_INCREMENT
  204.  * is defined at the top of this file, every instance will be actual
  205.  * so for the ones that we don't want to use it we just do ++/--
  206.  */
  207. STDMETHODIMP_(ULONG32) 
  208. MemoryMapManager::AddRef()
  209. {
  210.     return InterlockedIncrement(&m_lRefCount);
  211. }
  212. STDMETHODIMP_(ULONG32) 
  213. MemoryMapManager::Release()
  214. {
  215.     if (InterlockedDecrement(&m_lRefCount) > 0)
  216.     {
  217.         return m_lRefCount;
  218.     }
  219.     delete this;
  220. #ifdef _WIN32
  221.     MemoryMapDataFile::m_zpMMM = NULL;
  222. #endif
  223.     return 0;
  224. }
  225. void
  226. MemoryMapManager::ProcessIdle()
  227. {
  228.     LockMutex();
  229.     m_ulActiveReapList = (m_ulActiveReapList + 1) % NUMBER_OF_REAP_BUCKETS;
  230.     EmptyReapBuckets();
  231.     /*
  232.      * Note: This callback is always called on Streamer #1 on NT, so the first
  233.      * streamer to be spawned will reap dead pages for all other processes.
  234.      */
  235.     m_pMMMCallback->m_hPendingHandle =m_pScheduler->RelativeEnter(
  236. m_pMMMCallback, MS_BETWEEN_HANDLE_REAP_BUCKETS);
  237.     UnlockMutex();
  238.     return;
  239. }
  240. /*
  241.  * This context is from the correct process to charge the descriptor usage
  242.  * against.
  243.  */
  244.  
  245. void*
  246. MemoryMapManager::GetMMHandle(FILE_IDENTIFIER Descriptor)
  247. {
  248.     char pLookup[128]; /* Flawfinder: ignore */
  249.     UINT32 ulSize = 0;
  250. #ifdef _UNIX
  251.     struct stat s;
  252.     if (fstat(Descriptor, &s) == 0)
  253.     {
  254. if (!s.st_dev || !s.st_ino)
  255. {
  256.     return 0;
  257. }
  258. #ifdef _RED_HAT_5_X_
  259.     /* Why make devices 64 bit??? */
  260. sprintf (pLookup, "%lld,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
  261. #else
  262. sprintf (pLookup, "%d,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
  263. #endif
  264. ASSERT(s.st_dev);
  265. ASSERT(s.st_ino);
  266. ulSize = (UINT32)s.st_size;
  267. MMAPDPRINTF(("%p: GetHandle %d %d %ld  ", this,
  268.     Descriptor, s.st_dev, s.st_ino));
  269.     }
  270. #elif defined(_WINDOWS)
  271.     BY_HANDLE_FILE_INFORMATION FileInformation;
  272.     if (GetFileInformationByHandle(Descriptor, &FileInformation))
  273.     {
  274. sprintf (pLookup, "%x,%x,%x", FileInformation.nFileIndexLow, /* Flawfinder: ignore */
  275.     FileInformation.nFileIndexHigh, FileInformation.dwVolumeSerialNumber);
  276. ulSize = FileInformation.nFileSizeLow;
  277. MMAPDPRINTF(("%p: '%s'n", Descriptor, pLookup));
  278.     }
  279. #endif
  280.     if (ulSize == 0)
  281.     {
  282. return 0;
  283.     }
  284.     void* pVoid = NULL;
  285.     LockMutex();
  286.     m_pDevINodeToFileInfoMap->Lookup(pLookup, pVoid);
  287.     UnlockMutex();
  288.     return pVoid;
  289. }
  290. void*
  291. MemoryMapManager::OpenMap(FILE_IDENTIFIER Descriptor, IUnknown* pContext)
  292. {
  293.     char pLookup[128]; /* Flawfinder: ignore */
  294.     UINT32 ulSize = 0;
  295.     if (m_bDisableMemoryMappedIO)
  296.     {
  297. return NULL;
  298.     }
  299. #ifdef _UNIX
  300.     struct stat s;
  301.     if (fstat(Descriptor, &s) == 0)
  302.     {
  303. if (!s.st_dev || !s.st_ino)
  304. {
  305.     return 0;
  306. }
  307. #ifdef _RED_HAT_5_X_
  308. /* Why make devices 64 bit??? */
  309. sprintf (pLookup, "%lld,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
  310. #else
  311. sprintf (pLookup, "%d,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
  312. #endif
  313. ASSERT(s.st_dev);
  314. ASSERT(s.st_ino);
  315. ulSize = (UINT32)s.st_size;
  316. MMAPDPRINTF(("%p: OpenMap %d %d %ld  ", this,
  317.     Descriptor, s.st_dev, s.st_ino));
  318.     }
  319. #elif defined(_WINDOWS)
  320.     BY_HANDLE_FILE_INFORMATION FileInformation;
  321.     if (GetFileInformationByHandle(Descriptor, &FileInformation))
  322.     {
  323. sprintf (pLookup, "%x,%x,%x", FileInformation.nFileIndexLow, /* Flawfinder: ignore */
  324.     FileInformation.nFileIndexHigh, FileInformation.dwVolumeSerialNumber);
  325. ulSize = FileInformation.nFileSizeLow;
  326. MMAPDPRINTF(("%p: '%s'n", Descriptor, pLookup));
  327.     }
  328. #endif
  329.     if (ulSize == 0)
  330.     {
  331. return 0;
  332.     }
  333.     void* pVoid = NULL;
  334.     struct _FileInfo* pInfo = NULL;
  335.     LockMutex();
  336.     m_pDevINodeToFileInfoMap->Lookup(pLookup, pVoid);
  337.     if (pVoid)
  338.     {
  339. MMAPDPRINTF(("(OpenMap Found Already)n"));
  340. pInfo = (struct _FileInfo*) pVoid;
  341. HX_ASSERT (pInfo->Descriptor != 0);
  342. pInfo->ulRefCount++;
  343. pInfo->ulUseCount++;
  344. /* In case the file size has changed */
  345. pInfo->ulSize = ulSize;
  346. UnlockMutex();
  347. return pVoid;
  348.     }
  349.     else
  350.     {
  351. MMAPDPRINTF(("(OpenMap New)n"));
  352. #ifdef _UNIX
  353. m_pDevINodeToFileInfoMap->SetAt(pLookup, pInfo = new struct _FileInfo);
  354. pInfo->Descriptor = dup(Descriptor);
  355. #else
  356. HANDLE hTest = CreateFileMapping(Descriptor, NULL, PAGE_READWRITE, 0, 0, NULL);
  357. if (!hTest)
  358. {
  359.     /*
  360.      * Try to open the mapping for read only.  This is supposed to handle
  361.      * readonly files.  If the file was opened for write then this
  362.      * will fail anyway, so we can't really do the wrong thing here.
  363.      */
  364.     hTest = CreateFileMapping(Descriptor, NULL, PAGE_READONLY, 0, 0, NULL);
  365.     if (!hTest)
  366.     {
  367. UnlockMutex();
  368. return NULL;
  369.     }
  370. }
  371. m_pDevINodeToFileInfoMap->SetAt(pLookup, pInfo = new struct _FileInfo);
  372. pInfo->Descriptor = hTest;
  373. #endif
  374. SafeStrCpy(pInfo->pKey, pLookup, FILEINFO_KEY_SIZE);
  375. pInfo->ulSize = ulSize;
  376. pInfo->pMgr = this;
  377. pInfo->pMgr->AddRef();
  378. pInfo->ulRefCount = 1;
  379. pInfo->ulUseCount = 1;
  380. #ifdef _WIN32
  381. pInfo->m_pPTEList = NULL;
  382. #endif
  383. memset(pInfo->pPageTable, 0, sizeof (pInfo->pPageTable));
  384. if (HXR_OK == pContext->QueryInterface(IID_IHXDescriptorRegistration,
  385.     (void **)&pInfo->pDescReg))
  386. {
  387.     pInfo->pDescReg->RegisterDescriptors(1);
  388. }
  389. else
  390. {
  391.     pInfo->pDescReg = NULL;
  392. }
  393. UnlockMutex();
  394. return (void *)pInfo;
  395.     }
  396. }
  397. #ifdef _WIN32
  398. void
  399. MemoryMapManager::AttemptCloseMapNow(void* pHandle)
  400. {
  401.     LockMutex();
  402.     struct _FileInfo* pInfo = (struct _FileInfo*)pHandle;
  403.     _PageTableEntry* pPTE;
  404.     _PageTableEntry* pNextPTE;
  405.     pNextPTE = pInfo->m_pPTEList;
  406.     while (pNextPTE)
  407.     {
  408. pPTE = pNextPTE;
  409. pNextPTE = pPTE->m_pNextPTE;
  410. pPTE->bReapMe = TRUE;
  411. CheckAndReapPageTableEntry(pPTE);
  412.     }
  413.     UnlockMutex();
  414. }
  415. #endif
  416. void
  417. MemoryMapManager::CloseMap(void* pHandle)
  418. {
  419.     LockMutex();
  420.     MMAPDPRINTF(("CloseMapn"));
  421.     struct _FileInfo* pInfo = (struct _FileInfo*)pHandle;
  422.     pInfo->ulRefCount--;
  423.     pInfo->ulUseCount--;
  424.     if (pInfo->ulRefCount == 0)
  425.     {
  426.         DestroyFileInfo(pHandle);
  427.     }
  428. #if 0
  429.     /*
  430.      * This code is really slow and not needed.  These pages will be
  431.      * reaped shortly by the timed reaper.
  432.      */
  433.     if (pInfo->ulUseCount == 0)
  434.     {
  435. for (int i = 0; i < NUM_PTES; i++)
  436. {
  437.     if (pInfo->pPageTable[i] == NULL)
  438.     {
  439. continue;
  440.     }
  441.     struct _PageTableEntry* pIE = 0;
  442.     for (int j = 0; j < NUM_PTES; j++)
  443.     {
  444. pIE = (struct _PageTableEntry*)
  445.     &(pInfo->pPageTable[i]->pEntry[j]);
  446. if (pIE->bActive == FALSE)
  447. {
  448.     continue;
  449. }
  450. pIE->bReapMe = TRUE;
  451. CheckAndReapPageTableEntry(pIE);
  452. if (pInfo->pPageTable[i] == NULL)
  453. {
  454.     break;
  455. }
  456.     }
  457. }
  458.     }
  459. #endif
  460.     MMAPDPRINTF(("Done CloseMapn"));
  461.     UnlockMutex();
  462. }
  463. /*
  464.  * On _WIN32 whoever calls this MUST have the mUTex!!!
  465.  */
  466. void MemoryMapManager::EmptyReapBuckets()
  467. {
  468. #if defined  _MMM_NEED_MUTEX && defined _DEBUG
  469.     HX_ASSERT(m_bHaveMutex);
  470. #endif
  471.     UINT32 ulListToReap = (m_ulActiveReapList + 1) % NUMBER_OF_REAP_BUCKETS;
  472.     if (!ReapBuckets[ulListToReap].IsEmpty())
  473.     {
  474. CHXSimpleList* pList = &ReapBuckets[ulListToReap];
  475. struct _PageTableEntry* pIE = 0;
  476. LISTPOSITION l = pList->GetHeadPosition();
  477. LISTPOSITION temp;
  478. while (l)
  479. {
  480.     pIE = (struct _PageTableEntry*)pList->GetAt(l);
  481.     pIE->bReapMe = TRUE;
  482.     temp = l;
  483.     pList->GetNext(l);
  484.     if (CheckAndReapPageTableEntry(pIE) == FALSE)
  485.     {
  486. pIE->bDeadPage = TRUE;
  487. pList->RemoveAt(temp);
  488.     }
  489.     else
  490.     {
  491.     }
  492. }
  493.     }
  494. }
  495. UINT32
  496. MemoryMapManager::GetBlock(REF(IHXBuffer*) pBuffer, void* pHandle,
  497.     UINT32 ulOffset, UINT32 ulSize)
  498. {
  499.     LockMutex();
  500.     struct _FileInfo* pInfo = (struct _FileInfo*)pHandle;
  501.     UINT32 ulNeededPageNumber = (ulOffset / m_ulChunkSize);
  502.     UINT32 ulNeededL1Entry = ulNeededPageNumber / NUM_PTES;
  503.     UINT32 ulNeededL2Entry = ulNeededPageNumber % NUM_PTES;
  504.     struct _PageTableEntry* pEntry = 0;
  505. #ifdef MMAPMOREDEBUG
  506.     MMAPDPRINTF(("%p GetBlock %d %d, Page %d/%dn", pHandle, ulOffset, ulSize,
  507.     ulNeededL1Entry, ulNeededL2Entry));
  508.     fflush(0);
  509. #endif
  510.     if (ulOffset >= pInfo->ulSize)
  511.     {
  512. /* Maybe the file has grown */
  513. #ifdef _UNIX
  514. struct stat s;
  515. if (fstat(pInfo->Descriptor, &s) == 0)
  516. {
  517.     pInfo->ulSize = (UINT32)s.st_size;
  518. }
  519. #elif defined(_WINDOWS)
  520.         BY_HANDLE_FILE_INFORMATION FileInformation;
  521.         if (GetFileInformationByHandle(pInfo->Descriptor, &FileInformation))
  522. {
  523.     pInfo->ulSize = FileInformation.nFileSizeLow;
  524. }
  525. #endif
  526. if (ulOffset >= pInfo->ulSize)
  527. {
  528.     pBuffer = NULL;
  529.     UnlockMutex();
  530.     return (ULONG32) MMAP_EOF_EXCEPTION;
  531. }
  532.     }
  533.     if (pInfo->pPageTable[ulNeededL1Entry])
  534.     {
  535. if (pInfo->pPageTable[ulNeededL1Entry]->pEntry[ulNeededL2Entry].bActive)
  536. {
  537.     pEntry = &pInfo->pPageTable[ulNeededL1Entry]->
  538. pEntry[ulNeededL2Entry];
  539. }
  540.     }
  541.     UCHAR* ulDataPointer = 0;
  542.     if (!pEntry)
  543.     {
  544. UINT32 ulEmptyAttempts = 0;
  545. while (g_ulAddressSpaceUsed > MAX_ADDRESS_SPACE_USED &&
  546.     ulEmptyAttempts++ <
  547.     NUMBER_OF_REAP_BUCKETS_TO_EMPTY_ON_ADDRESS_SPACE_EXHUSTED)
  548. {
  549.     /*
  550.      * Attempt to unmap some old pages and hopefully free up
  551.      * some address space.
  552.      */
  553.     m_ulActiveReapList = (m_ulActiveReapList + 1)
  554. % NUMBER_OF_REAP_BUCKETS;
  555.     EmptyReapBuckets();
  556. }
  557. if (g_ulAddressSpaceUsed > MAX_ADDRESS_SPACE_USED)
  558. {
  559.     MMAPDPRINTF((" Address Space Exceeded, Exceptionn"));
  560.     UnlockMutex();
  561.     return MMAP_EXCEPTION;
  562. }
  563. if (pInfo->pPageTable[ulNeededL1Entry] == NULL)
  564. {
  565.     pInfo->pPageTable[ulNeededL1Entry] = 
  566. new struct MemoryMapManager::_PageTableLevel1;
  567.     memset(pInfo->pPageTable[ulNeededL1Entry], 0, sizeof(
  568. struct MemoryMapManager::_PageTableLevel1));
  569.     pInfo->pPageTable[ulNeededL1Entry]->
  570. ulNumberOfPageTableEntriesInUse = 0;
  571.     pInfo->pPageTable[ulNeededL1Entry]->
  572. pMyEntryInParentsPageTable =
  573. &pInfo->pPageTable[ulNeededL1Entry];
  574. #ifdef _WIN32
  575.     pInfo->m_pPTEList = NULL;
  576. #endif
  577. }
  578. pInfo->pPageTable[ulNeededL1Entry]->
  579.     ulNumberOfPageTableEntriesInUse++;
  580. pEntry = &pInfo->pPageTable[ulNeededL1Entry]->pEntry[ulNeededL2Entry];
  581. pEntry->bActive = TRUE;
  582. pEntry->bReapMe = FALSE;
  583. pEntry->bDeadPage = FALSE;
  584. pEntry->ulPageRefCount = 0;
  585. pEntry->pParent = pInfo->pPageTable[ulNeededL1Entry];
  586. pEntry->pInfo = pInfo;
  587. UINT32 ulChunkSize = m_ulChunkSize + MMAP_EXTRA_SLOP_SIZE;
  588. if (ulChunkSize + ulNeededPageNumber * m_ulChunkSize > pInfo->ulSize)
  589. {
  590.     ulChunkSize = pInfo->ulSize - ulNeededPageNumber * m_ulChunkSize;
  591. }
  592. pEntry->ulSize = ulChunkSize;
  593. pInfo->ulRefCount++;
  594. #ifdef _BEOS // no mmap for BeOS yet...
  595. pEntry->pPage = MAP_FAIL;
  596. #else
  597. #ifdef _UNIX
  598. pEntry->pPage =
  599.     mmap(0, ulChunkSize, PROT_READ, MAP_PRIVATE, 
  600.     pInfo->Descriptor, ulNeededPageNumber * m_ulChunkSize);
  601. #else
  602. pEntry->pPage = MapViewOfFile(pInfo->Descriptor, FILE_MAP_READ, 0,
  603.     ulNeededPageNumber * m_ulChunkSize, ulChunkSize);
  604. if (pEntry->pPage == 0)
  605. {
  606.     pEntry->pPage = MAP_FAIL;
  607. }
  608. else
  609. {
  610. #if !defined(HELIX_FEATURE_SERVER) && defined(_WINDOWS)
  611.             // When MapViewOfFile is called it returns a handle to a page of memory that
  612.             // the system no longer knows about so an exception occurs.  It is usally a 
  613.             // EXCEPTION_IN_PAGE_ERROR. Reading the documentation it appears that all access
  614.             // to handles returned from memory mapped I/O should be wrapped in try/catch blocks 
  615.             // since the handles may be invalid.  I added try/catch logic to test this out and
  616.             // it fixes the bug.  The main problem I'm not sure about is that this code is also 
  617.             // used by the server and IsBadReadPtr may iterate over the memory block which can 
  618.             // be slow.  Because this is the layer of code that "knows" it is using memory mapped 
  619.             // I/O this is probably where the try/catch code belongs so that if an exception
  620.             // occurs then it can return an error and no buffer since the buffer wouldn't be
  621.             // accessible anyway.
  622.             BOOL bInvalid = TRUE;
  623.             try
  624.             {
  625.                bInvalid = ::IsBadReadPtr(pEntry->pPage, ulChunkSize);
  626.             }
  627.             catch (...)
  628.             {
  629.             }
  630.             if (bInvalid)
  631.             {
  632.                pEntry->pPage = MAP_FAIL;
  633.             }
  634.             else
  635.             {
  636.                 if (pInfo->m_pPTEList)
  637.                 {
  638.                     pInfo->m_pPTEList->m_pPrevPTE = pEntry;
  639.                 }
  640.                 pEntry->m_pNextPTE = pInfo->m_pPTEList;
  641.                 pEntry->m_pPrevPTE = NULL;
  642.                 pInfo->m_pPTEList = pEntry;
  643.             }
  644. #else
  645.     if (pInfo->m_pPTEList)
  646.     {
  647. pInfo->m_pPTEList->m_pPrevPTE = pEntry;
  648.     }
  649.     pEntry->m_pNextPTE = pInfo->m_pPTEList;
  650.     pEntry->m_pPrevPTE = NULL;
  651.     pInfo->m_pPTEList = pEntry;
  652. #endif /* !HELIX_FEATURE_SERVER && _WINDOWS */
  653. }
  654. #endif
  655. #endif /* _BEOS */
  656. MMAPDPRINTF(("MMAP from %d Size %ld Pos %ld = %p (entry %p)n",
  657.     pInfo->Descriptor, ulChunkSize,
  658.     ulNeededPageNumber * m_ulChunkSize,
  659.     pEntry->pPage, pEntry));
  660. g_ulAddressSpaceUsed += ulChunkSize;
  661. pEntry->usReapListNumber = m_ulActiveReapList;
  662. pEntry->ReapListPosition = ReapBuckets[m_ulActiveReapList].
  663.     AddHead(pEntry);
  664. if (pEntry->pPage == MAP_FAIL)
  665. {
  666.     pBuffer = NULL;
  667.     pEntry->bReapMe = TRUE;
  668.     CheckAndReapPageTableEntry(pEntry);
  669.     UnlockMutex();
  670.     return (UINT32) MMAP_EXCEPTION;
  671. }
  672.     }
  673.     else
  674.     {
  675. if (pEntry->bDeadPage ||
  676.     (m_ulActiveReapList != pEntry->usReapListNumber))
  677. {
  678.     if (pEntry->bDeadPage)
  679.     {
  680. MMAPDPRINTF(("UnDeadPage to %p!n", pEntry));
  681.      pEntry->bDeadPage = FALSE;
  682.     }
  683.     else
  684.     {
  685. ReapBuckets[pEntry->usReapListNumber].
  686.     RemoveAt(pEntry->ReapListPosition);
  687.     }
  688.     pEntry->usReapListNumber = m_ulActiveReapList;
  689.     pEntry->ReapListPosition = ReapBuckets[m_ulActiveReapList].
  690. AddHead(pEntry);
  691. }
  692. pEntry->bReapMe = FALSE;
  693.     }
  694.     ulDataPointer = ((UCHAR *) pEntry->pPage) + ulOffset % m_ulChunkSize;
  695.     /*
  696.      * Go back to normal read() if we are asking for something past
  697.      * the mapped region.
  698.      */
  699.     if ((ulOffset + ulSize > pInfo->ulSize) ||
  700.         (ulOffset % m_ulChunkSize + ulSize > pEntry->ulSize))
  701.     {
  702. /*
  703.  * If the file has grown, then the region we mapped may not be
  704.  * large enough, but we can remap it.  This is a rare optimization
  705.  * that we can do without.
  706.  */
  707. BOOL bEOF = (ulOffset + ulSize > pInfo->ulSize);
  708. MMAPDPRINTF((" Memory Map Page Overrun, Exceptionn"));
  709. pBuffer = NULL;
  710. if (!z_bWithinServer)
  711. {
  712.     // Do not defer clean-up of unused pages when in client
  713.     pEntry->bReapMe = TRUE;
  714.     CheckAndReapPageTableEntry(pEntry);
  715. }
  716. UnlockMutex();
  717. if (bEOF)
  718. {
  719.     return MMAP_EOF_EXCEPTION;
  720. }
  721. else
  722. {
  723.     return MMAP_EXCEPTION;
  724. }
  725.     }
  726.     pBuffer = new(m_pFastAlloc) Buffer(pEntry, ulDataPointer, ulSize);
  727.     if(pBuffer)
  728.     {
  729.         pBuffer->AddRef();
  730.     }
  731.     else
  732.     {
  733.         ulSize = 0;
  734.     }
  735.     UnlockMutex();
  736.     return ulSize;
  737. }
  738. /*
  739.  * On _WIN32 you MUST have the mutex to call this!
  740.  */
  741. BOOL
  742. MemoryMapManager::CheckAndReapPageTableEntry(struct _PageTableEntry* pPTE)
  743. {
  744. #if defined  _MMM_NEED_MUTEX && defined _DEBUG
  745.     HX_ASSERT(pPTE->pInfo->pMgr->m_bHaveMutex);
  746. #endif
  747.     struct _FileInfo* pInfo = pPTE->pInfo;
  748.     if (pPTE->ulPageRefCount == 0 && pPTE->bReapMe)
  749.     {
  750. MMAPDPRINTF(("Unmap Chunk %p %ld  ", pPTE->pPage, pPTE->ulSize));
  751. if (pPTE->pPage != MAP_FAIL)
  752. {
  753. #ifdef _BEOS
  754.     // no memory mapped IO for BeOS yet!
  755. #else
  756. #ifdef _UNIX
  757. #ifdef _SOLARIS
  758.     munmap((char*)(pPTE->pPage), pPTE->ulSize);
  759. #else
  760.     munmap(pPTE->pPage, pPTE->ulSize);
  761. #endif
  762. #else
  763.     UnmapViewOfFile(pPTE->pPage);
  764.     if (pPTE->m_pPrevPTE)
  765.     {
  766. pPTE->m_pPrevPTE->m_pNextPTE = pPTE->m_pNextPTE;
  767.     }
  768.     else
  769.     {
  770. pInfo->m_pPTEList = pPTE->m_pNextPTE;
  771.     }
  772.     if (pPTE->m_pNextPTE)
  773.     {
  774. pPTE->m_pNextPTE->m_pPrevPTE = pPTE->m_pPrevPTE;
  775.     }
  776. #endif
  777. #endif /* _BEOS */
  778. }
  779. pInfo->ulRefCount--;
  780. g_ulAddressSpaceUsed -= pPTE->ulSize;
  781. MMAPDPRINTF((" (Down to %0.2f), Reap %un",
  782.     g_ulAddressSpaceUsed
  783.     / (1.0 * pInfo->pMgr->m_ulChunkSize + MMAP_EXTRA_SLOP_SIZE),
  784.     pPTE->bReapMe));
  785. pPTE->bActive = FALSE;
  786. if (pPTE->bDeadPage == FALSE)
  787. {
  788.     pInfo->pMgr->ReapBuckets[pPTE->usReapListNumber].
  789. RemoveAt(pPTE->ReapListPosition);
  790. }
  791. if (--pPTE->pParent->ulNumberOfPageTableEntriesInUse == 0)
  792. {
  793.     struct _PageTableLevel1** pPTL1 =
  794. pPTE->pParent->pMyEntryInParentsPageTable;
  795.     *pPTL1 = 0;
  796.     delete pPTE->pParent;
  797. }
  798.         if (pInfo->ulRefCount == 0)
  799.             DestroyFileInfo((void*)pInfo);
  800. return TRUE;
  801.     }
  802.     return FALSE;
  803. }
  804. /*
  805.  * On _WIN32 you MUST have the mutex to call this!
  806.  */
  807. void
  808. MemoryMapManager::DestroyFileInfo(void* pHandle)
  809. {
  810. #if defined  _MMM_NEED_MUTEX && defined _DEBUG
  811.     HX_ASSERT(((struct _FileInfo*)pHandle)->pMgr->m_bHaveMutex);
  812. #endif
  813.     struct _FileInfo* pInfo = (struct _FileInfo*)pHandle;
  814.     MMAPDPRINTF(("Remove %s from %pn", pInfo->pKey,
  815. pInfo->pMgr->m_pDevINodeToFileInfoMap));
  816.     pInfo->pMgr->m_pDevINodeToFileInfoMap->RemoveKey
  817. ((const char *)pInfo->pKey);
  818.     /*
  819.      * Don't use MemoryMapManager's context!  You will credit the wrong
  820.      * process.
  821.      */
  822.     if (pInfo->pDescReg)
  823.     {
  824. pInfo->pDescReg->UnRegisterDescriptors(1);
  825. HX_RELEASE(pInfo->pDescReg);
  826.     }
  827. #ifdef _UNIX
  828.     close(pInfo->Descriptor);
  829. #else
  830.     CloseHandle(pInfo->Descriptor);
  831. #endif
  832.     HX_RELEASE(pInfo->pMgr);
  833.     delete pInfo;
  834. }
  835. MemoryMapManager::Buffer::Buffer(struct _PageTableEntry* pEntry, UCHAR* pData,
  836.     ULONG32 ulLength)
  837.     : m_lRefCount(0)
  838.     , m_ulLength(ulLength)
  839.     , m_pData(pData)
  840.     , m_pPTE(pEntry)
  841. {
  842.     ASSERT(m_pPTE);
  843.     m_pPTE->ulPageRefCount++;
  844. }
  845. MemoryMapManager::Buffer::~Buffer()
  846. {
  847.     MemoryMapManager* pMgr = m_pPTE->pInfo->pMgr;
  848.     pMgr->LockMutex();
  849.     m_pPTE->ulPageRefCount--;
  850.     if (!z_bWithinServer && !m_pPTE->ulPageRefCount)
  851.         m_pPTE->bReapMe = TRUE;
  852.     MemoryMapManager::CheckAndReapPageTableEntry(m_pPTE);
  853.     pMgr->UnlockMutex();
  854. }
  855. STDMETHODIMP
  856. MemoryMapManager::Buffer::QueryInterface(REFIID riid, void** ppvObj)
  857. {
  858. QInterfaceList qiList[] =
  859. {
  860. { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IUnknown*)this },
  861. { GET_IIDHANDLE(IID_IHXBuffer), (IUnknown*)(IHXBuffer*)this },
  862. };
  863.     return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);   
  864. }
  865. STDMETHODIMP_(ULONG32) 
  866. MemoryMapManager::Buffer::AddRef()
  867. {
  868.     m_lRefCount++;
  869.     return m_lRefCount;
  870. }
  871. STDMETHODIMP_(ULONG32) 
  872. MemoryMapManager::Buffer::Release()
  873. {
  874.     m_lRefCount--;
  875.     if (m_lRefCount > 0)
  876.     {
  877.         return m_lRefCount;
  878.     }
  879.     delete this;
  880.     return 0;
  881. }
  882. STDMETHODIMP
  883. MemoryMapManager::Buffer::Get(REF(UCHAR*) pData, REF(ULONG32) ulLength)
  884. {
  885.     pData = m_pData;
  886.     ulLength = m_ulLength;
  887.     return HXR_OK;
  888. }
  889. STDMETHODIMP
  890. MemoryMapManager::Buffer::Set(const UCHAR* pData, ULONG32 ulLength)
  891. {
  892.     /* XXXSMP We should support this. */
  893.     PANIC(("Internal Error mmgr/620"));
  894.     return HXR_UNEXPECTED;
  895. }
  896. STDMETHODIMP
  897. MemoryMapManager::Buffer::SetSize(ULONG32 ulLength)
  898. {
  899.     /* XXXSMP We should support this. */
  900.     if (ulLength < m_ulLength)
  901.     {
  902. m_ulLength = ulLength;
  903. return HXR_OK;
  904.     }
  905.     else
  906.     {
  907.     PANIC(("Internal Error mmgr/635"));
  908. return HXR_UNEXPECTED;
  909.     }
  910. }
  911. STDMETHODIMP_(ULONG32)
  912. MemoryMapManager::Buffer::GetSize()
  913. {
  914.     return m_ulLength;
  915. }
  916. STDMETHODIMP_(UCHAR*)
  917. MemoryMapManager::Buffer::GetBuffer()
  918. {
  919.     return m_pData;
  920. }
  921. // MemoryMapManager callback
  922. MMMCallback::MMMCallback(MemoryMapManager* pMMM)
  923.    :m_lRefCount(0)
  924.    ,m_pMMM(pMMM)
  925.    ,m_hPendingHandle(0)
  926. {
  927. }
  928. MMMCallback::~MMMCallback()
  929. {
  930. }
  931. STDMETHODIMP
  932. MMMCallback::QueryInterface(REFIID riid, void**ppvObj)
  933. {
  934. QInterfaceList qiList[] =
  935. {
  936. { GET_IIDHANDLE(IID_IUnknown), this },
  937. { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*) this },
  938. };
  939.     return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  940. }
  941. /////////////////////////////////////////////////////////////////////////
  942. //  Method:
  943. // IUnknown::AddRef
  944. //  Purpose:
  945. // Everyone usually implements this the same... feel free to use
  946. // this implementation.
  947. //
  948. STDMETHODIMP_(ULONG32) 
  949. MMMCallback::AddRef()
  950. {
  951.     m_lRefCount++;
  952.     return m_lRefCount;
  953. }
  954. /////////////////////////////////////////////////////////////////////////
  955. //  Method:
  956. // IUnknown::Release
  957. //  Purpose:
  958. // Everyone usually implements this the same... feel free to use
  959. // this implementation.
  960. //
  961. STDMETHODIMP_(ULONG32) 
  962. MMMCallback::Release()
  963. {
  964.     m_lRefCount--;
  965.     if (m_lRefCount > 0)
  966.     {
  967.         return m_lRefCount;
  968.     }
  969.     delete this;
  970.     return 0;
  971. }
  972. STDMETHODIMP
  973. MMMCallback::Func(void)
  974. {
  975.     m_hPendingHandle = 0;
  976.     if (m_pMMM)
  977.     {
  978. m_pMMM->AddRef();
  979. m_pMMM->ProcessIdle();
  980. m_pMMM->Release();
  981.     }
  982.     return HXR_OK;
  983. }
  984. #endif
  985. #endif /* _VXWORKS */