266 lines
8.1 KiB
C++
266 lines
8.1 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================//
|
|
|
|
#ifndef RESOURCEMANAGER_H
|
|
#define RESOURCEMANAGER_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "tier0/threadtools.h"
|
|
#include "utlmultilist.h"
|
|
#include "utlvector.h"
|
|
|
|
FORWARD_DECLARE_HANDLE(memhandle_t);
|
|
|
|
#define INVALID_MEMHANDLE ((memhandle_t)0xffffffff)
|
|
|
|
class CDataManagerBase {
|
|
public:
|
|
// public API
|
|
// -----------------------------------------------------------------------------
|
|
// memhandle_t CreateResource( params ) // implemented by derived
|
|
// class
|
|
void DestroyResource(memhandle_t handle);
|
|
|
|
// type-safe implementation in derived class
|
|
// void *LockResource( memhandle_t handle
|
|
// );
|
|
int UnlockResource(memhandle_t handle);
|
|
void TouchResource(memhandle_t handle);
|
|
void MarkAsStale(memhandle_t handle); // move to head of LRU
|
|
|
|
int LockCount(memhandle_t handle);
|
|
int BreakLock(memhandle_t handle);
|
|
int BreakAllLocks();
|
|
|
|
// HACKHACK: For convenience - offers no lock protection
|
|
// type-safe implementation in derived class
|
|
// void *GetResource_NoLock( memhandle_t handle
|
|
// );
|
|
|
|
unsigned int TargetSize();
|
|
unsigned int AvailableSize();
|
|
unsigned int UsedSize();
|
|
|
|
void NotifySizeChanged(memhandle_t handle, unsigned int oldSize,
|
|
unsigned int newSize);
|
|
|
|
void SetTargetSize(unsigned int targetSize);
|
|
|
|
// NOTE: flush is equivalent to Destroy
|
|
unsigned int FlushAllUnlocked();
|
|
unsigned int FlushToTargetSize();
|
|
unsigned int FlushAll();
|
|
unsigned int Purge(unsigned int nBytesToPurge);
|
|
unsigned int EnsureCapacity(unsigned int size);
|
|
|
|
// Thread lock
|
|
virtual void Lock() {}
|
|
virtual bool TryLock() { return true; }
|
|
virtual void Unlock() {}
|
|
|
|
// Iteration
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Debugging only!!!!
|
|
void GetLRUHandleList(CUtlVector<memhandle_t> &list);
|
|
void GetLockHandleList(CUtlVector<memhandle_t> &list);
|
|
|
|
protected:
|
|
// derived class must call these to implement public API
|
|
unsigned short CreateHandle(bool bCreateLocked);
|
|
memhandle_t StoreResourceInHandle(unsigned short memoryIndex, void *pStore,
|
|
unsigned int realSize);
|
|
void *GetResource_NoLock(memhandle_t handle);
|
|
void *GetResource_NoLockNoLRUTouch(memhandle_t handle);
|
|
void *LockResource(memhandle_t handle);
|
|
|
|
// NOTE: you must call this from the destructor of the derived class! (will
|
|
// assert otherwise)
|
|
void FreeAllLists() {
|
|
FlushAll();
|
|
m_listsAreFreed = true;
|
|
}
|
|
|
|
CDataManagerBase(unsigned int maxSize);
|
|
virtual ~CDataManagerBase();
|
|
|
|
inline unsigned int MemTotal_Inline() const { return m_targetMemorySize; }
|
|
inline unsigned int MemAvailable_Inline() const {
|
|
return m_targetMemorySize - m_memUsed;
|
|
}
|
|
inline unsigned int MemUsed_Inline() const { return m_memUsed; }
|
|
|
|
// Implemented by derived class:
|
|
virtual void DestroyResourceStorage(void *) = 0;
|
|
virtual unsigned int GetRealSize(void *) = 0;
|
|
|
|
memhandle_t ToHandle(unsigned short index);
|
|
unsigned short FromHandle(memhandle_t handle);
|
|
|
|
void TouchByIndex(unsigned short memoryIndex);
|
|
void *GetForFreeByIndex(unsigned short memoryIndex);
|
|
|
|
// One of these is stored per active allocation
|
|
struct resource_lru_element_t {
|
|
resource_lru_element_t() {
|
|
lockCount = 0;
|
|
serial = 1;
|
|
pStore = 0;
|
|
}
|
|
|
|
unsigned short lockCount;
|
|
unsigned short serial;
|
|
void *pStore;
|
|
};
|
|
|
|
unsigned int m_targetMemorySize;
|
|
unsigned int m_memUsed;
|
|
|
|
CUtlMultiList<resource_lru_element_t, unsigned short> m_memoryLists;
|
|
|
|
unsigned short m_lruList;
|
|
unsigned short m_lockList;
|
|
unsigned short m_freeList;
|
|
unsigned short m_listsAreFreed : 1;
|
|
unsigned short m_unused : 15;
|
|
};
|
|
|
|
template <class STORAGE_TYPE, class CREATE_PARAMS,
|
|
class LOCK_TYPE = STORAGE_TYPE *, class MUTEX_TYPE = CThreadNullMutex>
|
|
class CDataManager : public CDataManagerBase {
|
|
typedef CDataManagerBase BaseClass;
|
|
|
|
public:
|
|
CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>(
|
|
unsigned int size = (unsigned)-1)
|
|
: BaseClass(size) {}
|
|
|
|
~CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>() {
|
|
// NOTE: This must be called in all implementations of CDataManager
|
|
FreeAllLists();
|
|
}
|
|
|
|
// Use GetData() to translate pointer to LOCK_TYPE
|
|
LOCK_TYPE LockResource(memhandle_t hMem) {
|
|
void *pLock = BaseClass::LockResource(hMem);
|
|
if (pLock) {
|
|
return StoragePointer(pLock)->GetData();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Use GetData() to translate pointer to LOCK_TYPE
|
|
LOCK_TYPE GetResource_NoLock(memhandle_t hMem) {
|
|
void *pLock = const_cast<void *>(BaseClass::GetResource_NoLock(hMem));
|
|
if (pLock) {
|
|
return StoragePointer(pLock)->GetData();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Use GetData() to translate pointer to LOCK_TYPE
|
|
// Doesn't touch the memory LRU
|
|
LOCK_TYPE GetResource_NoLockNoLRUTouch(memhandle_t hMem) {
|
|
void *pLock =
|
|
const_cast<void *>(BaseClass::GetResource_NoLockNoLRUTouch(hMem));
|
|
if (pLock) {
|
|
return StoragePointer(pLock)->GetData();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Wrapper to match implementation of allocation with typed storage & alloc
|
|
// params.
|
|
memhandle_t CreateResource(const CREATE_PARAMS &createParams,
|
|
bool bCreateLocked = false) {
|
|
BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams));
|
|
unsigned short memoryIndex = BaseClass::CreateHandle(bCreateLocked);
|
|
STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource(createParams);
|
|
return BaseClass::StoreResourceInHandle(memoryIndex, pStore,
|
|
pStore->Size());
|
|
}
|
|
|
|
// Iteration. Must lock first
|
|
memhandle_t GetFirstUnlocked() {
|
|
unsigned node = m_memoryLists.Head(m_lruList);
|
|
if (node == m_memoryLists.InvalidIndex()) {
|
|
return INVALID_MEMHANDLE;
|
|
}
|
|
return ToHandle(node);
|
|
}
|
|
|
|
memhandle_t GetFirstLocked() {
|
|
unsigned node = m_memoryLists.Head(m_lockList);
|
|
if (node == m_memoryLists.InvalidIndex()) {
|
|
return INVALID_MEMHANDLE;
|
|
}
|
|
return ToHandle(node);
|
|
}
|
|
|
|
memhandle_t GetNext(memhandle_t hPrev) {
|
|
if (hPrev == INVALID_MEMHANDLE) {
|
|
return INVALID_MEMHANDLE;
|
|
}
|
|
|
|
unsigned short iNext = m_memoryLists.Next(FromHandle(hPrev));
|
|
if (iNext == m_memoryLists.InvalidIndex()) {
|
|
return INVALID_MEMHANDLE;
|
|
}
|
|
|
|
return ToHandle(iNext);
|
|
}
|
|
|
|
MUTEX_TYPE &AccessMutex() { return m_mutex; }
|
|
virtual void Lock() { m_mutex.Lock(); }
|
|
virtual bool TryLock() { return m_mutex.TryLock(); }
|
|
virtual void Unlock() { m_mutex.Unlock(); }
|
|
|
|
private:
|
|
STORAGE_TYPE *StoragePointer(void *pMem) {
|
|
return static_cast<STORAGE_TYPE *>(pMem);
|
|
}
|
|
|
|
virtual void DestroyResourceStorage(void *pStore) {
|
|
StoragePointer(pStore)->DestroyResource();
|
|
}
|
|
|
|
virtual unsigned int GetRealSize(void *pStore) {
|
|
return StoragePointer(pStore)->Size();
|
|
}
|
|
|
|
MUTEX_TYPE m_mutex;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
inline unsigned short CDataManagerBase::FromHandle(memhandle_t handle) {
|
|
unsigned int fullWord = (unsigned int)handle;
|
|
unsigned short serial = fullWord >> 16;
|
|
unsigned short index = fullWord & 0xFFFF;
|
|
index--;
|
|
if (m_memoryLists.IsValidIndex(index) &&
|
|
m_memoryLists[index].serial == serial)
|
|
return index;
|
|
return m_memoryLists.InvalidIndex();
|
|
}
|
|
|
|
inline int CDataManagerBase::LockCount(memhandle_t handle) {
|
|
Lock();
|
|
int result = 0;
|
|
unsigned short memoryIndex = FromHandle(handle);
|
|
if (memoryIndex != m_memoryLists.InvalidIndex()) {
|
|
result = m_memoryLists[memoryIndex].lockCount;
|
|
}
|
|
Unlock();
|
|
return result;
|
|
}
|
|
|
|
#endif // RESOURCEMANAGER_H
|