⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmapmgr.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ***** BEGIN LICENSE BLOCK ***** 
 * Version: RCSL 1.0/RPSL 1.0 
 *  
 * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
 *      
 * The contents of this file, and the files included with this file, are 
 * subject to the current version of the RealNetworks Public Source License 
 * Version 1.0 (the "RPSL") available at 
 * http://www.helixcommunity.org/content/rpsl unless you have licensed 
 * the file under the RealNetworks Community Source License Version 1.0 
 * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
 * in which case the RCSL will apply. You may also obtain the license terms 
 * directly from RealNetworks.  You may not use this file except in 
 * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
 * applicable to this file, the RCSL.  Please see the applicable RPSL or 
 * RCSL for the rights, obligations and limitations governing use of the 
 * contents of the file.  
 *  
 * This file is part of the Helix DNA Technology. RealNetworks is the 
 * developer of the Original Code and owns the copyrights in the portions 
 * it created. 
 *  
 * This file, and the files included with this file, is distributed and made 
 * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
 * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 * 
 * Technology Compatibility Kit Test Suite(s) Location: 
 *    http://www.helixcommunity.org/content/tck 
 * 
 * Contributor(s): 
 *  
 * ***** END LICENSE BLOCK ***** */ 

// no memory map support on VXWORKS or Symbian
#if !defined(_VXWORKS) && !defined(_SYMBIAN)

/*
 * MMapMgr needs atomic ref increments.
 */
#define _WIN32_USE_INTERLOCKED_INCREMENT
#include "hxcom.h"
#include "hxtypes.h"
#ifndef _MACINTOSH

#include <stdio.h>
#include <stdlib.h>

#ifdef _UNIX
#include <unistd.h>
#include <fcntl.h>
#endif

#include "hlxclib/sys/types.h"
#include "hlxclib/sys/stat.h"
#include "hlxclib/io.h"

#if defined(_UNIX) && !defined(_BEOS)
#include <sys/mman.h>
#endif

#include "hxbuffer.h"
#include "hxstrutl.h"
#include "hxmap.h"
#include "hxengin.h"
#include "mmapmgr.h"
#include "hxspriv.h"
#include "debug.h"
#include "mmapdatf.h"
#include "hxassert.h"
#include "hxmon.h"

#ifdef _MMM_NEED_MUTEX
#include "hxcomm.h"
#endif

//#define  MMAPDEBUG
//#define  MMAPMOREDEBUG

#ifdef MMAPDEBUG
#define MMAPDPRINTF(x) printf x
#else
#define MMAPDPRINTF(x)
#endif

/* Must be a multiple of the page size */
#define MMAP_INITIAL_CHUNK_SIZE						\
		(256 * 1024)

#define MMAP_EXTRA_SLOP_SIZE						\
		65536

#define MAX_ADDRESS_SPACE_USED						\
		1 * 1024 * 1000 * 1000	// 1 Gig

#define MS_BETWEEN_HANDLE_REAP_BUCKETS					\
		3000

#define NUMBER_OF_REAP_BUCKETS_TO_EMPTY_ON_ADDRESS_SPACE_EXHUSTED	\
		2


#ifndef MAP_FAIL
#define MAP_FAIL ((void *)-1)
#endif

/*
 * On Linux/NT we have 1 address space for all procs.  On other unicies we
 * have 'n' processes and 'n' address spaces.  This variables tracks address
 * usage correctly on all 3 types of OSes.
 */
UINT32     g_ulAddressSpaceUsed = 0;


/*
 *  On the server we wish to reap the memory after a little bit of time
 *  because it is very likely that we will want to use it again in a 
 *  short amount of time. On the client we do not wish to do this, becuase we
 *  can not do good things like delete the file if it is mem-mapped.
 */

static BOOL z_bDeterminedIfWeAreWithinServer    = FALSE;
static BOOL z_bWithinServer                     = FALSE;

/*
 * On NT we only have one MemoryMapManager per server.
 * On other unix platforms, we have on MemoryMapManager
 * per process.
 *
 * XXXSMP The Linux code is Sub-Optimal!!  Since we have 1 address space,
 * we should take advantage of the fact that pages that we are trying to
 * map in one thread may already be mapped by another thread.  With 'n'
 * MMM's, we can't take advantage of this optimization.
 */
MemoryMapManager::MemoryMapManager(IUnknown* pContext,
	BOOL bDisableMemoryMappedIO, UINT32 ulChunkSize)
    : m_pMMMCallback(NULL)
{
    m_pDevINodeToFileInfoMap = new CHXMapStringToOb;
    m_pDevINodeToFileInfoMap->InitHashTable(517);
    m_ulActiveReapList = 0;

    HX_VERIFY (HXR_OK ==
	pContext->QueryInterface(IID_IHXScheduler, (void **)&m_pScheduler));

    if (!z_bDeterminedIfWeAreWithinServer)
    {
        z_bDeterminedIfWeAreWithinServer = TRUE;

        IHXRegistry* pHXReg = NULL;

        pContext->QueryInterface(IID_IHXRegistry, (void **)&pHXReg);
        if (pHXReg)
        {
            HXPropType type = pHXReg->GetTypeByName("server.version");
            if (type!= PT_UNKNOWN)
            {
                z_bWithinServer = TRUE;
            }
            HX_RELEASE(pHXReg);
        }
    }

    if (ulChunkSize)
    {
	m_ulChunkSize = ulChunkSize;
    }
    else
    {
	m_ulChunkSize = MMAP_INITIAL_CHUNK_SIZE;
    }
    m_lRefCount = 0;

    if (z_bWithinServer)
    {
	m_pMMMCallback = new MMMCallback(this);

	if (m_pMMMCallback)
	{
	    m_pMMMCallback->AddRef();
	    m_pMMMCallback->m_hPendingHandle = m_pScheduler->RelativeEnter(m_pMMMCallback, MS_BETWEEN_HANDLE_REAP_BUCKETS);
	}
    }

#ifdef _MMM_NEED_MUTEX
    m_pMutex = NULL;
#ifdef _DEBUG
    m_bHaveMutex = FALSE;
#endif
    IHXCommonClassFactory* pCCF;
    if (HXR_OK == pContext->QueryInterface(IID_IHXCommonClassFactory,
	(void**)&pCCF))
    {
	pCCF->CreateInstance(CLSID_IHXMutex, (void**)&m_pMutex);
	pCCF->Release();
    }
#endif
    m_pFastAlloc = NULL;
    pContext->QueryInterface(IID_IHXFastAlloc, (void **)&m_pFastAlloc);
    m_bDisableMemoryMappedIO = bDisableMemoryMappedIO;
}


MemoryMapManager::~MemoryMapManager()
{
    /* This had better be empty by now!! */
    HX_DELETE(m_pDevINodeToFileInfoMap);

    if (m_pMMMCallback && m_pMMMCallback->m_hPendingHandle)
    {
	m_pScheduler->Remove(m_pMMMCallback->m_hPendingHandle);
    }
    HX_RELEASE(m_pMMMCallback);

    HX_RELEASE(m_pScheduler);
    HX_RELEASE(m_pFastAlloc);

#ifdef _MMM_NEED_MUTEX
    HX_RELEASE(m_pMutex);
#endif
}


STDMETHODIMP
MemoryMapManager::QueryInterface(REFIID riid, void** ppvObj)
{
    if (IsEqualIID(riid, IID_IUnknown))
    {
        AddRef();
        *ppvObj = (IUnknown*)(IUnknown*)this;
        return HXR_OK;
    }

    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}


/*
 * These are the only AddRef/Release pairs
 * that need to be thread safe.  All the
 * other don't need to be.  Since _WIN32_USE_INTERLOCKED_INCREMENT
 * is defined at the top of this file, every instance will be actual
 * so for the ones that we don't want to use it we just do ++/--
 */
STDMETHODIMP_(ULONG32) 
MemoryMapManager::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}


STDMETHODIMP_(ULONG32) 
MemoryMapManager::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;

#ifdef _WIN32
    MemoryMapDataFile::m_zpMMM = NULL;
#endif

    return 0;
}


void
MemoryMapManager::ProcessIdle()
{
    LockMutex();
    m_ulActiveReapList = (m_ulActiveReapList + 1) % NUMBER_OF_REAP_BUCKETS;

    EmptyReapBuckets();

    /*
     * Note: This callback is always called on Streamer #1 on NT, so the first
     * streamer to be spawned will reap dead pages for all other processes.
     */
    m_pMMMCallback->m_hPendingHandle =m_pScheduler->RelativeEnter(
	m_pMMMCallback, MS_BETWEEN_HANDLE_REAP_BUCKETS);

    UnlockMutex();
    return;
}


/*
 * This context is from the correct process to charge the descriptor usage
 * against.
 */
 
void*
MemoryMapManager::GetMMHandle(FILE_IDENTIFIER Descriptor)
{
    char pLookup[128]; /* Flawfinder: ignore */
    UINT32 ulSize = 0;

#ifdef _UNIX
    struct stat s;

    if (fstat(Descriptor, &s) == 0)
    {
	if (!s.st_dev || !s.st_ino)
	{
	    return 0;
	}

#ifdef _RED_HAT_5_X_
    /* Why make devices 64 bit??? */
	sprintf (pLookup, "%lld,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
#else
	sprintf (pLookup, "%d,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
#endif
	ASSERT(s.st_dev);
	ASSERT(s.st_ino);
	ulSize = (UINT32)s.st_size;

	MMAPDPRINTF(("%p: GetHandle %d %d %ld  ", this,
	    Descriptor, s.st_dev, s.st_ino));
    }
#elif defined(_WINDOWS)
    BY_HANDLE_FILE_INFORMATION FileInformation;

    if (GetFileInformationByHandle(Descriptor, &FileInformation))
    {
	sprintf (pLookup, "%x,%x,%x", FileInformation.nFileIndexLow, /* Flawfinder: ignore */
	    FileInformation.nFileIndexHigh, FileInformation.dwVolumeSerialNumber);

	ulSize = FileInformation.nFileSizeLow;

	MMAPDPRINTF(("%p: '%s'\n", Descriptor, pLookup));
    }
#endif

    if (ulSize == 0)
    {
	return 0;
    }

    void* pVoid = NULL;
    LockMutex();
    m_pDevINodeToFileInfoMap->Lookup(pLookup, pVoid);
    UnlockMutex();
    return pVoid;
}

void*
MemoryMapManager::OpenMap(FILE_IDENTIFIER Descriptor, IUnknown* pContext)
{
    char pLookup[128]; /* Flawfinder: ignore */
    UINT32 ulSize = 0;

    if (m_bDisableMemoryMappedIO)
    {
	return NULL;
    }

#ifdef _UNIX
    struct stat s;

    if (fstat(Descriptor, &s) == 0)
    {
	if (!s.st_dev || !s.st_ino)
	{
	    return 0;
	}

#ifdef _RED_HAT_5_X_
	/* Why make devices 64 bit??? */
	sprintf (pLookup, "%lld,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
#else
	sprintf (pLookup, "%d,%ld", s.st_dev, s.st_ino); /* Flawfinder: ignore */
#endif
	ASSERT(s.st_dev);
	ASSERT(s.st_ino);
	ulSize = (UINT32)s.st_size;

	MMAPDPRINTF(("%p: OpenMap %d %d %ld  ", this,
	    Descriptor, s.st_dev, s.st_ino));
    }
#elif defined(_WINDOWS)
    BY_HANDLE_FILE_INFORMATION FileInformation;

    if (GetFileInformationByHandle(Descriptor, &FileInformation))
    {
	sprintf (pLookup, "%x,%x,%x", FileInformation.nFileIndexLow, /* Flawfinder: ignore */
	    FileInformation.nFileIndexHigh, FileInformation.dwVolumeSerialNumber);

	ulSize = FileInformation.nFileSizeLow;

	MMAPDPRINTF(("%p: '%s'\n", Descriptor, pLookup));
    }
#endif

    if (ulSize == 0)
    {
	return 0;
    }

    void* pVoid = NULL;
    struct _FileInfo* pInfo = NULL;

    LockMutex();
    m_pDevINodeToFileInfoMap->Lookup(pLookup, pVoid);
    if (pVoid)
    {
	MMAPDPRINTF(("(OpenMap Found Already)\n"));
	pInfo = (struct _FileInfo*) pVoid;
	HX_ASSERT (pInfo->Descriptor != 0);
	pInfo->ulRefCount++;
	pInfo->ulUseCount++;
	/* In case the file size has changed */
	pInfo->ulSize = ulSize;

	UnlockMutex();
	return pVoid;
    }
    else
    {
	MMAPDPRINTF(("(OpenMap New)\n"));
#ifdef _UNIX
	m_pDevINodeToFileInfoMap->SetAt(pLookup, pInfo = new struct _FileInfo);
	pInfo->Descriptor = dup(Descriptor);
#else

	HANDLE hTest = CreateFileMapping(Descriptor, NULL, PAGE_READWRITE, 0, 0, NULL);
	if (!hTest)
	{
	    /*
	     * Try to open the mapping for read only.  This is supposed to handle
	     * readonly files.  If the file was opened for write then this
	     * will fail anyway, so we can't really do the wrong thing here.
	     */
	    hTest = CreateFileMapping(Descriptor, NULL, PAGE_READONLY, 0, 0, NULL);
	    if (!hTest)
	    {
		UnlockMutex();
		return NULL;
	    }
	}
	m_pDevINodeToFileInfoMap->SetAt(pLookup, pInfo = new struct _FileInfo);
	pInfo->Descriptor = hTest;
#endif
	SafeStrCpy(pInfo->pKey, pLookup, FILEINFO_KEY_SIZE);
	pInfo->ulSize = ulSize;
	pInfo->pMgr = this;
	pInfo->pMgr->AddRef();
	pInfo->ulRefCount = 1;
	pInfo->ulUseCount = 1;
#ifdef _WIN32
	pInfo->m_pPTEList = NULL;
#endif
	memset(pInfo->pPageTable, 0, sizeof (pInfo->pPageTable));
	if (HXR_OK == pContext->QueryInterface(IID_IHXDescriptorRegistration,
	    (void **)&pInfo->pDescReg))
	{
	    pInfo->pDescReg->RegisterDescriptors(1);
	}
	else
	{
	    pInfo->pDescReg = NULL;
	}

	UnlockMutex();
	return (void *)pInfo;
    }
}


#ifdef _WIN32
void
MemoryMapManager::AttemptCloseMapNow(void* pHandle)
{
    LockMutex();
    struct _FileInfo* pInfo = (struct _FileInfo*)pHandle;
    _PageTableEntry* pPTE;
    _PageTableEntry* pNextPTE;
    pNextPTE = pInfo->m_pPTEList;
    while (pNextPTE)
    {
	pPTE = pNextPTE;
	pNextPTE = pPTE->m_pNextPTE;
	pPTE->bReapMe = TRUE;
	CheckAndReapPageTableEntry(pPTE);
    }
    UnlockMutex();
}
#endif

void
MemoryMapManager::CloseMap(void* pHandle)
{
    LockMutex();
    MMAPDPRINTF(("CloseMap\n"));
    struct _FileInfo* pInfo = (struct _FileInfo*)pHandle;
    pInfo->ulRefCount--;
    pInfo->ulUseCount--;

    if (pInfo->ulRefCount == 0)
    {
        DestroyFileInfo(pHandle);
    }

#if 0
    /*
     * This code is really slow and not needed.  These pages will be
     * reaped shortly by the timed reaper.
     */
    if (pInfo->ulUseCount == 0)
    {
	for (int i = 0; i < NUM_PTES; i++)
	{
	    if (pInfo->pPageTable[i] == NULL)
	    {
		continue;
	    }

	    struct _PageTableEntry* pIE = 0;

	    for (int j = 0; j < NUM_PTES; j++)
	    {
		pIE = (struct _PageTableEntry*)
		    &(pInfo->pPageTable[i]->pEntry[j]);
		if (pIE->bActive == FALSE)
		{
		    continue;
		}
		pIE->bReapMe = TRUE;
		CheckAndReapPageTableEntry(pIE);
		if (pInfo->pPageTable[i] == NULL)
		{
		    break;
		}
	    }
	}
    }
#endif
    MMAPDPRINTF(("Done CloseMap\n"));

    UnlockMutex();
}


/*
 * On _WIN32 whoever calls this MUST have the mUTex!!!
 */
void MemoryMapManager::EmptyReapBuckets()
{
#if defined  _MMM_NEED_MUTEX && defined _DEBUG
    HX_ASSERT(m_bHaveMutex);
#endif

    UINT32 ulListToReap = (m_ulActiveReapList + 1) % NUMBER_OF_REAP_BUCKETS;

    if (!ReapBuckets[ulListToReap].IsEmpty())
    {
	CHXSimpleList* pList = &ReapBuckets[ulListToReap];
	struct _PageTableEntry* pIE = 0;
	LISTPOSITION l = pList->GetHeadPosition();
	LISTPOSITION temp;

	while (l)
	{
	    pIE = (struct _PageTableEntry*)pList->GetAt(l);
	    pIE->bReapMe = TRUE;
	    temp = l;
	    pList->GetNext(l);
	    if (CheckAndReapPageTableEntry(pIE) == FALSE)
	    {
		pIE->bDeadPage = TRUE;
		pList->RemoveAt(temp);
	    }
	    else
	    {
	    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -