You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
5.8 KiB
263 lines
5.8 KiB
/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
namedobj.cxx
|
|
|
|
Abstract:
|
|
|
|
Implements table-based creation and lookup services for
|
|
"pseudo"-named kernel objects. This allows unrelated bits
|
|
of code in the same process to find the same named objects
|
|
without actually creating a full-fledged named kernel
|
|
object.
|
|
|
|
Revision History:
|
|
|
|
JSimmons 02-28-02 Created
|
|
|
|
--*/
|
|
|
|
#include <or.hxx>
|
|
|
|
// Global ptr to object table
|
|
CNamedObjectTable* gpNamedObjectTable = NULL;
|
|
|
|
//
|
|
// CNameKey
|
|
//
|
|
// Used for lookups in the hash table. Not exposed outside
|
|
// this file.
|
|
//
|
|
class CNameKey : public CTableKey
|
|
{
|
|
public:
|
|
|
|
CNameKey(LPWSTR pszName, CNamedObject::OBJTYPE type) :
|
|
_pszName(pszName),
|
|
_type(type)
|
|
{
|
|
ASSERT(pszName);
|
|
ASSERT(CNamedObject::ValidObjType(type));
|
|
};
|
|
|
|
~CNameKey() {};
|
|
|
|
DWORD Hash()
|
|
{
|
|
LPCWSTR psz = _pszName;
|
|
unsigned long hash = 0x01234567;
|
|
while (*psz) hash = (hash << 5) + (hash >> 27) + *psz++;
|
|
return hash;
|
|
}
|
|
|
|
BOOL Compare(CTableKey &tk)
|
|
{
|
|
CNameKey& namekey = (CNameKey&)tk;
|
|
if (namekey._type != _type)
|
|
return FALSE;
|
|
return !lstrcmp(_pszName, namekey._pszName);
|
|
}
|
|
|
|
private:
|
|
const LPCWSTR _pszName; // someone else's ptr, we don't own it
|
|
CNamedObject::OBJTYPE _type;
|
|
};
|
|
|
|
|
|
CNamedObject::CNamedObject(HANDLE hHandle, OBJTYPE type, LPWSTR pszName) :
|
|
_hHandle(hHandle),
|
|
_type(type)
|
|
{
|
|
ASSERT(_hHandle);
|
|
ASSERT(ValidObjType(type));
|
|
ASSERT(pszName);
|
|
lstrcpy(_szName, pszName);
|
|
}
|
|
|
|
CNamedObject::~CNamedObject()
|
|
{
|
|
ASSERT(_hHandle);
|
|
CloseHandle(_hHandle);
|
|
}
|
|
|
|
DWORD CNamedObject::Release()
|
|
{
|
|
LONG lRefs = gpNamedObjectTable->ReleaseAndMaybeRemove(this);
|
|
if (lRefs == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return lRefs;
|
|
}
|
|
|
|
DWORD CNamedObject::Hash()
|
|
{
|
|
CNameKey mykey(_szName, _type);
|
|
return mykey.Hash();
|
|
}
|
|
|
|
BOOL CNamedObject::Compare(CTableKey &tk)
|
|
{
|
|
CNameKey& theirkey = (CNameKey&)tk;
|
|
CNameKey mykey(_szName, _type);
|
|
return mykey.Compare(theirkey);
|
|
}
|
|
|
|
BOOL CNamedObject::Compare(CONST CTableElement *element)
|
|
{
|
|
CNamedObject& namedobject = (CNamedObject&)*element;
|
|
CNameKey theirkey(namedobject._szName, namedobject._type);
|
|
CNameKey mykey(_szName, _type);
|
|
return mykey.Compare(theirkey);
|
|
}
|
|
|
|
BOOL CNamedObject::ValidObjType(OBJTYPE type)
|
|
{
|
|
return ((type >=OBJTYPE_MIN) && (type < OBJTYPE_MAX));
|
|
}
|
|
|
|
CNamedObject* CNamedObject::Create(OBJTYPE type, LPWSTR pszName)
|
|
{
|
|
HANDLE hNew = NULL;
|
|
CNamedObject* pObject = NULL;
|
|
|
|
hNew = CNamedObject::CreateHandle(type);
|
|
if (hNew)
|
|
{
|
|
DWORD dwObjectSize = (lstrlen(pszName)+1) * sizeof(WCHAR);
|
|
pObject = new(dwObjectSize) CNamedObject(hNew, type, pszName);
|
|
if (!pObject)
|
|
{
|
|
CloseHandle(hNew);
|
|
}
|
|
}
|
|
return pObject;
|
|
}
|
|
|
|
HANDLE CNamedObject::CreateHandle(OBJTYPE type)
|
|
{
|
|
HANDLE hNew = NULL;
|
|
|
|
switch (type)
|
|
{
|
|
case EVENT:
|
|
hNew = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
break;
|
|
case MUTEX:
|
|
hNew = CreateMutex(NULL, FALSE, NULL);
|
|
break;
|
|
default:
|
|
ASSERT(!"Caller specified incorrect object type");
|
|
break;
|
|
};
|
|
|
|
return hNew;
|
|
}
|
|
|
|
//
|
|
// GetNamedObject
|
|
//
|
|
// Meat of the table. Take read lock, look for existing object, if
|
|
// found, return it.. Else, take write lock, look again for existing
|
|
// object, if found return it, else create new object, save it in the
|
|
// table, return it.
|
|
//
|
|
CNamedObject* CNamedObjectTable::GetNamedObject(
|
|
LPWSTR pszObjName,
|
|
CNamedObject::OBJTYPE type)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CNamedObject* pObject = NULL;
|
|
CNameKey namekey(pszObjName, type);
|
|
|
|
_pLock->LockShared();
|
|
|
|
pObject = (CNamedObject*)_pHashTbl->Lookup(namekey);
|
|
if (pObject)
|
|
{
|
|
pObject->Reference();
|
|
_pLock->UnlockShared();
|
|
}
|
|
else
|
|
{
|
|
// Didn't find it. Take write lock, look again
|
|
_pLock->ConvertToExclusive();
|
|
|
|
pObject = (CNamedObject*)_pHashTbl->Lookup(namekey);
|
|
if (!pObject)
|
|
{
|
|
pObject = CNamedObject::Create(type, pszObjName);
|
|
if (pObject)
|
|
{
|
|
_pHashTbl->Add(pObject); // 1 reference keeping it alive in the table
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// found an existing one after taking the lock
|
|
pObject->Reference();
|
|
}
|
|
|
|
_pLock->UnlockExclusive();
|
|
}
|
|
|
|
return pObject;
|
|
}
|
|
|
|
//
|
|
// ReleaseAndMaybeRemove
|
|
//
|
|
// CNamedObject's use this method to perform an atomic refcount
|
|
// decrement + potential removal from the table.
|
|
//
|
|
LONG CNamedObjectTable::ReleaseAndMaybeRemove(CNamedObject* pObject)
|
|
{
|
|
LONG lRefs = 0;
|
|
|
|
ASSERT(pObject);
|
|
|
|
_pLock->LockExclusive();
|
|
|
|
if (pObject->References() == 1)
|
|
{
|
|
_pHashTbl->Remove(pObject);
|
|
}
|
|
|
|
lRefs = pObject->Dereference();
|
|
|
|
_pLock->UnlockExclusive();
|
|
|
|
return lRefs;
|
|
}
|
|
|
|
// constructor
|
|
CNamedObjectTable::CNamedObjectTable(ORSTATUS& status) :
|
|
_pHashTbl(NULL),
|
|
_pLock(NULL)
|
|
{
|
|
status = OR_NOMEM;
|
|
_pHashTbl = new CHashTable(status);
|
|
if (status == OR_OK)
|
|
{
|
|
status = OR_NOMEM;
|
|
_pLock = new CSharedLock(status);
|
|
}
|
|
}
|
|
|
|
// destructor
|
|
CNamedObjectTable::~CNamedObjectTable()
|
|
{
|
|
// We live for the life of the RPCSS service so cleanup is
|
|
// not a high priority. If our lifetime is ever shortened
|
|
// to something less we'll need to do better.
|
|
//delete _pHashTbl;
|
|
//delete _pLock;
|
|
}
|
|
|
|
|
|
|
|
|
|
|