dvander@218: #ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ dvander@218: #define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ dvander@218: dvander@218: #include dvander@218: #include "sm_globals.h" dvander@218: #include "sm_trie.h" dvander@218: #include "sourcemod.h" dvander@218: #include "sm_memtable.h" dvander@218: dvander@222: #define HANDLESYS_MAX_HANDLES (1<<14) dvander@218: #define HANDLESYS_MAX_TYPES (1<<9) dvander@218: #define HANDLESYS_MAX_SUBTYPES 0xF dvander@218: #define HANDLESYS_SUBTYPE_MASK 0xF dvander@218: #define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1)) dvander@218: #define HANDLESYS_MAX_SERIALS 0xFFFF dvander@218: #define HANDLESYS_SERIAL_MASK 0xFFFF0000 dvander@218: #define HANDLESYS_HANDLE_MASK 0x0000FFFF dvander@218: dvander@229: /** dvander@229: * The QHandle is a nasty structure that compacts the handle system into a big vector. dvander@229: * The members of the vector each encapsulate one Handle, however, they also act as nodes dvander@229: * in an inlined linked list and an inlined vector. dvander@229: * dvander@229: * The first of these lists is the 'freeID' list. Each node from 1 to N (where N dvander@229: * is the number of free nodes) has a 'freeID' that specifies a free Handle ID. This dvander@229: * is a quick hack to get around allocating a second base vector. dvander@229: * dvander@229: * The second vector is the identity linked list. An identity has its own handle, so dvander@229: * these handles are used as sentinel nodes for index linking. They point to the first and last dvander@229: * index into the handle array. Each subsequent Handle who is owned by that indentity is mapped into dvander@229: * that list. This lets owning identities be unloaded in O(n) time. dvander@229: * dvander@229: * Eventually, there may be a third list for type chains. dvander@229: */ dvander@229: dvander@229: enum HandleSet dvander@229: { dvander@229: HandleSet_None = 0, dvander@229: HandleSet_Used, dvander@229: HandleSet_Identity dvander@229: }; dvander@229: dvander@218: struct QHandle dvander@218: { dvander@222: HandleType_t type; /* Handle type */ dvander@222: void *object; /* Unmaintained object pointer */ dvander@229: IdentityToken_t *owner; /* Identity of object which owns this */ dvander@222: unsigned int serial; /* Serial no. for sanity checking */ dvander@222: unsigned int refcount; /* Reference count for safe destruction */ dvander@222: Handle_t clone; /* If non-zero, this is our cloned parent */ dvander@229: HandleSet set; /* Information about the handle's state */ dvander@229: /* The following variables are unrelated to the Handle array, and used dvander@229: * as an inlined chain of information */ dvander@229: unsigned int freeID; /* ID of a free handle in the free handle chain */ dvander@229: /* Indexes into the handle array for owner membership. dvander@229: * For identity roots, these are treated as the head/tail. */ dvander@229: unsigned int ch_prev; /* chained previous handle or HEAD */ dvander@229: unsigned int ch_next; /* chained next handle or TAIL */ dvander@218: }; dvander@218: dvander@218: struct QHandleType dvander@218: { dvander@218: IHandleTypeDispatch *dispatch; dvander@218: unsigned int freeID; dvander@218: unsigned int children; dvander@218: HandleSecurity sec; dvander@218: unsigned int opened; dvander@218: int nameIdx; dvander@218: }; dvander@218: dvander@218: class HandleSystem : dvander@218: public IHandleSys dvander@218: { dvander@229: friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index); dvander@229: friend class ShareSystem; dvander@218: public: dvander@218: HandleSystem(); dvander@218: ~HandleSystem(); dvander@218: public: //IHandleSystem dvander@218: HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch); dvander@218: HandleType_t CreateTypeEx(const char *name, dvander@218: IHandleTypeDispatch *dispatch, dvander@218: HandleType_t parent, dvander@229: const HandleSecurity *security, dvander@229: IdentityToken_t *ident); dvander@218: HandleType_t CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch); dvander@229: bool RemoveType(HandleType_t type, IdentityToken_t *ident); dvander@218: bool FindHandleType(const char *name, HandleType_t *type); dvander@218: Handle_t CreateHandle(HandleType_t type, dvander@218: void *object, dvander@229: IdentityToken_t *source, dvander@229: IdentityToken_t *ident); dvander@252: Handle_t CreateScriptHandle(HandleType_t type, void *object, IPluginContext *pContext, IdentityToken_t *ident); dvander@229: HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident); dvander@229: HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident); dvander@229: HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object); dvander@229: bool TypeCheck(HandleType_t intype, HandleType_t outtype); dvander@229: protected: dvander@222: /** dvander@222: * Decodes a handle with sanity and security checking. dvander@222: */ dvander@222: HandleError GetHandle(Handle_t handle, dvander@229: IdentityToken_t *ident, dvander@222: QHandle **pHandle, dvander@222: unsigned int *index, dvander@222: HandleAccessRight access); dvander@222: dvander@222: /** dvander@222: * Creates a basic handle and sets its reference count to 1. dvander@222: * Does not do any type or security checking. dvander@222: */ dvander@229: HandleError MakePrimHandle(HandleType_t type, dvander@229: QHandle **pHandle, dvander@229: unsigned int *index, dvander@229: HandleType_t *handle, dvander@229: IdentityToken_t *owner); dvander@222: dvander@222: /** dvander@229: * Frees a primitive handle. Does no object freeing, only reference count, bookkeepping, dvander@229: * and linked list maintenance. dvander@222: */ dvander@222: void ReleasePrimHandle(unsigned int index); dvander@229: dvander@229: /** dvander@229: * Sets the security owner of a type dvander@229: */ dvander@229: void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken); dvander@229: dvander@229: /** dvander@229: * Marks a handle as an identity. dvander@229: * This prevents it from being tampered with by outside stuff dvander@229: */ dvander@229: void MarkHandleAsIdentity(Handle_t handle); dvander@222: private: dvander@218: QHandle *m_Handles; dvander@218: QHandleType *m_Types; dvander@218: Trie *m_TypeLookup; dvander@218: unsigned int m_TypeTail; dvander@218: unsigned int m_FreeTypes; dvander@218: unsigned int m_HandleTail; dvander@218: unsigned int m_FreeHandles; dvander@218: unsigned int m_HSerial; dvander@218: BaseStringTable *m_strtab; dvander@218: }; dvander@218: dvander@218: extern HandleSystem g_HandleSys; dvander@218: dvander@218: #endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_