Handle system can now unload identities safely. when an identity is removed, all handles owned by it are removed in a chain.

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40288
This commit is contained in:
David Anderson 2007-01-11 07:29:09 +00:00
parent 09b01f7950
commit efd3a8ab5f
6 changed files with 188 additions and 150 deletions

View File

@ -203,10 +203,6 @@
RelativePath="..\sm_autonatives.cpp"
>
</File>
<File
RelativePath="..\sm_hl2utils.cpp"
>
</File>
<File
RelativePath="..\sm_memtable.cpp"
>
@ -396,6 +392,10 @@
<Filter
Name="Interfaces"
>
<File
RelativePath="..\interfaces\IExtensionSys.h"
>
</File>
<File
RelativePath="..\interfaces\IForwardSys.h"
>
@ -408,10 +408,6 @@
RelativePath="..\interfaces\ILibrarySys.h"
>
</File>
<File
RelativePath="..\interfaces\IModuleSys.h"
>
</File>
<File
RelativePath="..\interfaces\IPluginFunction.h"
>

View File

@ -30,6 +30,8 @@ inline const char *StatusToStr(PluginStatus st)
return "Uncompiled";
case Plugin_BadLoad:
return "Bad Load";
case Plugin_Failed:
return "Failed";
default:
assert(false);
return "-";

View File

@ -428,26 +428,12 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
return 1;
}
//:TODO: DEBUG CODE HERE
cell_t PrintStuff(IPluginContext *pContext, const cell_t *params)
{
char *stuff;
pContext->LocalToString(params[1], &stuff);
FILE *fp = fopen("c:\\debug.txt", "at");
fprintf(fp, "%s\n", stuff);
fclose(fp);
return 0;
}
static FileNatives s_FileNatives;
REGISTER_NATIVES(filesystem)
{
{"OpenDirectory", sm_OpenDirectory},
{"ReadDirEntry", sm_ReadDirEntry},
{"PrintStuff", PrintStuff},//:TODO: remove this when no longer needed
{"OpenFile", sm_OpenFile},
{"DeleteFile", sm_DeleteFile},
{"ReadFileLine", sm_ReadFileLine},

View File

@ -231,7 +231,8 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
QHandle **in_pHandle,
unsigned int *in_index,
Handle_t *in_handle,
IdentityToken_t *owner)
IdentityToken_t *owner,
bool identity)
{
unsigned int owner_index = 0;
@ -262,7 +263,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
}
/* Set essential information */
pHandle->set = HandleSet_Used;;
pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
pHandle->refcount = 1;
pHandle->type = type;
pHandle->serial = m_HSerial;
@ -282,8 +283,10 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
*in_index = handle;
*in_handle = hash;
/* Decode the identity token */
if (owner)
/* Decode the identity token
* For now, we don't allow nested ownership
*/
if (owner && !identity)
{
QHandle *pIdentity = &m_Handles[owner_index];
if (pIdentity->ch_prev == 0)
@ -319,7 +322,7 @@ void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pTok
m_Types[type].typeSec.ident = pToken;
}
Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity)
{
if (!type
|| type >= HANDLESYS_TYPEARRAY_SIZE
@ -335,8 +338,8 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok
/* Check to see if we're allowed to create this handle type */
QHandleType *pType = &m_Types[type];
if (!pType->typeSec.access[HTypeAccess_Create]
&& (!pType->typeSec.ident
|| pType->typeSec.ident != ident))
&& (!pType->typeSec.ident
|| pType->typeSec.ident != ident))
{
if (err)
{
@ -350,7 +353,7 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok
QHandle *pHandle;
HandleError _err;
if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner)) != HandleError_None)
if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
{
if (err)
{
@ -365,6 +368,11 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok
return handle;
}
Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
{
return CreateHandleEx(type, object, owner, ident, err, false);
}
bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
{
/* Check the type inheritance */
@ -453,6 +461,27 @@ bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const
return true;
}
HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
{
/* Get a new Handle ID */
unsigned int new_index;
QHandle *pNewHandle;
Handle_t new_handle;
HandleError err;
if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
{
return err;
}
pNewHandle->clone = index;
pHandle->refcount++;
*newhandle = new_handle;
return HandleError_None;
}
HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
{
HandleError err;
@ -477,20 +506,63 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, Iden
return HandleError_Access;
}
/* Get a new Handle ID */
unsigned int new_index;
QHandle *pNewHandle;
Handle_t new_handle;
if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
/* Make sure we're not cloning a clone */
if (pHandle->clone)
{
return err;
QHandle *pParent = &m_Handles[pHandle->clone];
return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
}
pNewHandle->clone = index;
pHandle->refcount++;
return CloneHandle(pHandle, index, newhandle, newOwner);
}
*newhandle = new_handle;
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
{
QHandleType *pType = &m_Types[pHandle->type];
if (pHandle->clone)
{
/* If we're a clone, decrease the parent reference count */
QHandle *pMaster;
unsigned int master;
/* Note that if we ever have per-handle security, we would need to re-check
* the access on this Handle. */
master = pHandle->clone;
pMaster = &m_Handles[master];
/* Release the clone now */
ReleasePrimHandle(index);
/* Decrement the master's reference count */
if (--pMaster->refcount == 0)
{
/* Type should be the same but do this anyway... */
pType = &m_Types[pMaster->type];
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
ReleasePrimHandle(master);
}
} else if (pHandle->set == HandleSet_Identity) {
/* If we're an identity, skip all this stuff!
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
*/
ReleasePrimHandle(index);
} else {
/* Decrement, free if necessary */
if (--pHandle->refcount == 0)
{
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
ReleasePrimHandle(index);
} else {
/* We must be cloned, so mark ourselves as freed */
pHandle->set = HandleSet_Freed;
/* Now, unlink us, so we're not being tracked by the owner */
if (pHandle->owner)
{
UnlinkHandleFromOwner(pHandle, index);
}
}
}
return HandleError_None;
}
@ -512,44 +584,7 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec
return HandleError_Access;
}
QHandleType *pType = &m_Types[pHandle->type];
bool dofree = false;
if (pHandle->clone)
{
/* If we're a clone, decrease the parent reference count */
QHandle *pMaster;
unsigned int master;
/* Note that if we ever have per-handle security, we would need to re-check
* the access on this Handle. */
master = pHandle->clone;
pMaster = &m_Handles[master];
/* Release the clone now */
ReleasePrimHandle(index);
/* Decrement the master's reference count */
if (--pMaster->refcount == 0)
{
/* Type should be the same but do this anyway... */
pType = &m_Types[pMaster->type];
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
ReleasePrimHandle(master);
}
} else {
/* Decrement, free if necessary */
if (--pHandle->refcount == 0)
{
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
ReleasePrimHandle(index);
} else {
/* We must be cloned, so mark ourselves as freed */
pHandle->set = HandleSet_Freed;
}
}
return HandleError_None;
return FreeHandle(pHandle, index);
}
HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
@ -597,60 +632,84 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const H
return HandleError_None;
}
void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
{
/* Unlink us if necessary */
unsigned int ident_index;
if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
{
/* Uh-oh! */
assert(pHandle->owner == 0);
return;
}
/* Note that since 0 is an invalid handle, if any of these links are 0,
* the data can still be set.
*/
QHandle *pIdentity = &m_Handles[ident_index];
/* Unlink case: We're the head AND tail node */
if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
{
pIdentity->ch_prev = 0;
pIdentity->ch_next = 0;
}
/* Unlink case: We're the head node */
else if (index == pIdentity->ch_prev) {
/* Link us to the next in the chain */
pIdentity->ch_prev = pHandle->ch_next;
/* Patch up the previous link */
m_Handles[pHandle->ch_next].ch_prev = 0;
}
/* Unlink case: We're the tail node */
else if (index == pIdentity->ch_next) {
/* Link us to the previous in the chain */
pIdentity->ch_next = pHandle->ch_prev;
/* Patch up the next link */
m_Handles[pHandle->ch_prev].ch_next = 0;
}
/* Unlink case: We're in the middle! */
else {
/* Patch the forward reference */
m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
/* Patch the backward reference */
m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
}
/* Lastly, decrease the reference count */
pIdentity->refcount--;
}
void HandleSystem::ReleasePrimHandle(unsigned int index)
{
QHandle *pHandle = &m_Handles[index];
HandleSet set = pHandle->set;
if (pHandle->owner && (set != HandleSet_Identity))
{
UnlinkHandleFromOwner(pHandle, index);
}
/* Were we an identity ourself? */
QHandle *pLocal;
if (set == HandleSet_Identity)
{
/* Extra work to do. We need to find everything connected to this identity and release it. */
unsigned int ch_index, old_index = 0;
while ((ch_index = pHandle->ch_next) != 0)
{
pLocal = &m_Handles[ch_index];
#if defined _DEBUG
assert(old_index != ch_index);
assert(pLocal->set == HandleSet_Used);
old_index = ch_index;
#endif
FreeHandle(pLocal, ch_index);
}
}
pHandle->set = HandleSet_None;
m_Types[pHandle->type].opened--;
m_Handles[++m_FreeHandles].freeID = index;
/* Unlink us if necessary */
if (pHandle->owner)
{
unsigned int ident_index;
if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
{
/* Uh-oh! */
assert(pHandle->owner == 0);
return;
}
/* Note that since 0 is an invalid handle, if any of these links are 0,
* the data can still be set.
*/
QHandle *pIdentity = &m_Handles[ident_index];
/* Unlink case: We're the head AND tail node */
if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
{
pIdentity->ch_prev = 0;
pIdentity->ch_next = 0;
}
/* Unlink case: We're the head node */
else if (index == pIdentity->ch_prev) {
/* Link us to the next in the chain */
pIdentity->ch_prev = pHandle->ch_next;
/* Patch up the previous link */
m_Handles[pHandle->ch_next].ch_prev = 0;
}
/* Unlink case: We're the tail node */
else if (index == pIdentity->ch_next) {
/* Link us to the previous in the chain */
pIdentity->ch_next = pHandle->ch_prev;
/* Patch up the next link */
m_Handles[pHandle->ch_prev].ch_next = 0;
}
/* Unlink case: We're in the middle! */
else {
/* Patch the forward reference */
m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
/* Patch the backward reference */
m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
}
/* Lastly, decrease the reference count */
pIdentity->refcount--;
}
}
bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
@ -737,19 +796,6 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
return true;
}
void HandleSystem::MarkHandleAsIdentity(Handle_t handle)
{
QHandle *pHandle;
unsigned int index;
if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index) != HandleError_None)
{
return;
}
pHandle->set = HandleSet_Identity;
}
bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
{
if (pTypeAccess)

View File

@ -55,8 +55,8 @@ struct QHandle
unsigned int freeID; /* ID of a free handle in the free handle chain */
/* Indexes into the handle array for owner membership.
* For identity roots, these are treated as the head/tail. */
unsigned int ch_prev; /* chained previous handle or HEAD */
unsigned int ch_next; /* chained next handle or TAIL */
unsigned int ch_prev; /* chained previous handle */
unsigned int ch_next; /* chained next handle */
};
struct QHandleType
@ -97,6 +97,7 @@ public: //IHandleSystem
IdentityToken_t *owner,
IdentityToken_t *ident,
HandleError *err);
HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
HandleError CloneHandle(Handle_t handle,
@ -130,26 +131,33 @@ protected:
QHandle **pHandle,
unsigned int *index,
HandleType_t *handle,
IdentityToken_t *owner);
IdentityToken_t *owner,
bool identity=false);
/**
* Frees a primitive handle. Does no object freeing, only reference count, bookkeepping,
* and linked list maintenance.
* If used on an Identity handle, destroys all Handles under that identity.
*/
void ReleasePrimHandle(unsigned int index);
/**
* Sets the security owner of a type
* Sets the security owner of a type.
*/
void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
/**
* Marks a handle as an identity.
* This prevents it from being tampered with by outside stuff
/**
* Helper function to check access rights.
*/
void MarkHandleAsIdentity(Handle_t handle);
bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
/**
* Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
*/
HandleError FreeHandle(QHandle *pHandle, unsigned int index);
void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
Handle_t CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity);
private:
QHandle *m_Handles;
QHandleType *m_Types;

View File

@ -73,7 +73,7 @@ IdentityType_t ShareSystem::CreateIdentType(const char *name)
void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
{
/* We don't care here */
/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
}
IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
@ -85,7 +85,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
/* :TODO: Cache? */
IdentityToken_t *pToken = new IdentityToken_t;
pToken->ident = g_HandleSys.CreateHandle(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL);
pToken->ident = g_HandleSys.CreateHandleEx(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL, true);
return pToken;
}