core/systems/HandleSys.h
author David Anderson <dvander@alliedmods.net>
Mon Oct 22 16:48:54 2007 +0000 (2007-10-22)
changeset 1639 5c7fffd146ae
parent 1638 2980312c1c94
child 1687 47cc645edce6
permissions -rw-r--r--
fixed linux build
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@370
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@370
    28
 *
dvander@370
    29
 * Version: $Id$
dvander@370
    30
 */
dvander@370
    31
dvander@218
    32
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
dvander@218
    33
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
dvander@218
    34
dvander@218
    35
#include <IHandleSys.h>
dvander@900
    36
#include <stdio.h>
dvander@218
    37
#include "sm_globals.h"
dvander@218
    38
#include "sm_trie.h"
dvander@218
    39
#include "sourcemod.h"
dvander@218
    40
#include "sm_memtable.h"
dvander@218
    41
dvander@222
    42
#define HANDLESYS_MAX_HANDLES		(1<<14)
dvander@218
    43
#define HANDLESYS_MAX_TYPES			(1<<9)
dvander@218
    44
#define HANDLESYS_MAX_SUBTYPES		0xF
dvander@218
    45
#define HANDLESYS_SUBTYPE_MASK		0xF
dvander@218
    46
#define HANDLESYS_TYPEARRAY_SIZE	(HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
dvander@218
    47
#define HANDLESYS_MAX_SERIALS		0xFFFF
dvander@218
    48
#define HANDLESYS_SERIAL_MASK		0xFFFF0000
dvander@218
    49
#define HANDLESYS_HANDLE_MASK		0x0000FFFF
dvander@218
    50
dvander@229
    51
/**
dvander@229
    52
 *   The QHandle is a nasty structure that compacts the handle system into a big vector.
dvander@229
    53
 * The members of the vector each encapsulate one Handle, however, they also act as nodes
dvander@229
    54
 * in an inlined linked list and an inlined vector.
dvander@229
    55
 *
dvander@229
    56
 *   The first of these lists is the 'freeID' list.  Each node from 1 to N (where N
dvander@229
    57
 * is the number of free nodes) has a 'freeID' that specifies a free Handle ID.  This
dvander@229
    58
 * is a quick hack to get around allocating a second base vector.
dvander@229
    59
 *
dvander@229
    60
 *   The second vector is the identity linked list.  An identity has its own handle, so
dvander@229
    61
 * these handles are used as sentinel nodes for index linking.  They point to the first and last
ds@487
    62
 * index into the handle array.  Each subsequent Handle who is owned by that identity is mapped into
dvander@229
    63
 * that list.  This lets owning identities be unloaded in O(n) time.
dvander@229
    64
 *
dvander@229
    65
 *   Eventually, there may be a third list for type chains.
dvander@229
    66
 */
dvander@229
    67
dvander@229
    68
enum HandleSet
dvander@229
    69
{
dvander@229
    70
	HandleSet_None = 0,
dvander@259
    71
	HandleSet_Used,			/* The Handle is in use */
dvander@259
    72
	HandleSet_Freed,		/* The "master" Handle of a clone chain is freed */
dvander@259
    73
	HandleSet_Identity,		/* The Handle is a special identity */
dvander@229
    74
};
dvander@229
    75
dvander@218
    76
struct QHandle
dvander@218
    77
{
dvander@222
    78
	HandleType_t type;			/* Handle type */
dvander@222
    79
	void *object;				/* Unmaintained object pointer */
dvander@229
    80
	IdentityToken_t *owner;		/* Identity of object which owns this */
dvander@222
    81
	unsigned int serial;		/* Serial no. for sanity checking */
dvander@222
    82
	unsigned int refcount;		/* Reference count for safe destruction */
dvander@262
    83
	unsigned int clone;			/* If non-zero, this is our cloned parent index */
dvander@229
    84
	HandleSet set;				/* Information about the handle's state */
dvander@528
    85
	bool access_special;		/* Whether or not access rules are special or type-derived */
dvander@789
    86
	bool is_destroying;			/* Whether or not the handle is being destroyed */
dvander@528
    87
	HandleAccess sec;			/* Security rules */
dvander@229
    88
	/* The following variables are unrelated to the Handle array, and used 
dvander@229
    89
	 * as an inlined chain of information */
dvander@229
    90
	unsigned int freeID;		/* ID of a free handle in the free handle chain */
dvander@229
    91
	/* Indexes into the handle array for owner membership.
dvander@229
    92
	 * For identity roots, these are treated as the head/tail. */
dvander@283
    93
	unsigned int ch_prev;		/* chained previous handle */
dvander@283
    94
	unsigned int ch_next;		/* chained next handle */
dvander@218
    95
};
dvander@218
    96
dvander@218
    97
struct QHandleType
dvander@218
    98
{
dvander@218
    99
	IHandleTypeDispatch *dispatch;
dvander@218
   100
	unsigned int freeID;
dvander@218
   101
	unsigned int children;
dvander@262
   102
	TypeAccess typeSec;
dvander@262
   103
	HandleAccess hndlSec;
dvander@218
   104
	unsigned int opened;
dvander@218
   105
	int nameIdx;
dvander@218
   106
};
dvander@218
   107
dvander@218
   108
class HandleSystem : 
dvander@218
   109
	public IHandleSys
dvander@218
   110
{
dvander@229
   111
	friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index);
dvander@229
   112
	friend class ShareSystem;
dvander@218
   113
public:
dvander@218
   114
	HandleSystem();
dvander@218
   115
	~HandleSystem();
dvander@218
   116
public: //IHandleSystem
dvander@262
   117
dvander@262
   118
	HandleType_t CreateType(const char *name,
dvander@262
   119
		IHandleTypeDispatch *dispatch,
dvander@262
   120
		HandleType_t parent,
dvander@262
   121
		const TypeAccess *typeAccess,
dvander@262
   122
		const HandleAccess *hndlAccess,
dvander@262
   123
		IdentityToken_t *ident,
dvander@262
   124
		HandleError *err);
dvander@262
   125
dvander@229
   126
	bool RemoveType(HandleType_t type, IdentityToken_t *ident);
dvander@262
   127
dvander@218
   128
	bool FindHandleType(const char *name, HandleType_t *type);
dvander@262
   129
dvander@218
   130
	Handle_t CreateHandle(HandleType_t type, 
dvander@262
   131
		void *object,
dvander@262
   132
		IdentityToken_t *owner,
dvander@262
   133
		IdentityToken_t *ident,
dvander@262
   134
		HandleError *err);
dvander@283
   135
dvander@262
   136
	HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
dvander@262
   137
dvander@262
   138
	HandleError CloneHandle(Handle_t handle, 
dvander@262
   139
		Handle_t *newhandle, 
dvander@262
   140
		IdentityToken_t *newOwner,
dvander@262
   141
		const HandleSecurity *pSecurity);
dvander@262
   142
dvander@262
   143
	HandleError ReadHandle(Handle_t handle, 
dvander@262
   144
		HandleType_t type, 
dvander@262
   145
		const HandleSecurity *pSecurity,
dvander@262
   146
		void **object);
dvander@262
   147
dvander@262
   148
	bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess);
dvander@262
   149
dvander@229
   150
	bool TypeCheck(HandleType_t intype, HandleType_t outtype);
dvander@528
   151
dvander@528
   152
	virtual Handle_t CreateHandleEx(HandleType_t type, 
dvander@528
   153
		void *object,
dvander@528
   154
		const HandleSecurity *pSec,
dvander@528
   155
		const HandleAccess *pAccess,
dvander@528
   156
		HandleError *err);
dvander@900
   157
dvander@900
   158
	void Dump(FILE *fp);
dvander@229
   159
protected:
dvander@222
   160
	/**
dvander@222
   161
	 * Decodes a handle with sanity and security checking.
dvander@222
   162
	 */
dvander@222
   163
	HandleError GetHandle(Handle_t handle, 
dvander@229
   164
						  IdentityToken_t *ident, 
dvander@222
   165
						  QHandle **pHandle, 
dvander@222
   166
						  unsigned int *index,
dvander@259
   167
						  bool ignoreFree=false);
dvander@222
   168
dvander@222
   169
	/**
dvander@222
   170
	 * Creates a basic handle and sets its reference count to 1.
dvander@222
   171
	 * Does not do any type or security checking.
dvander@222
   172
	 */
dvander@229
   173
	HandleError MakePrimHandle(HandleType_t type, 
dvander@229
   174
							   QHandle **pHandle, 
dvander@229
   175
							   unsigned int *index, 
dvander@229
   176
							   HandleType_t *handle,
dvander@283
   177
							   IdentityToken_t *owner,
dvander@283
   178
							   bool identity=false);
dvander@222
   179
dvander@222
   180
	/**
ds@729
   181
	 * Frees a primitive handle.  Does no object freeing, only reference count, bookkeeping, 
dvander@229
   182
	 * and linked list maintenance.
dvander@283
   183
	 * If used on an Identity handle, destroys all Handles under that identity.
dvander@222
   184
	 */
dvander@222
   185
	void ReleasePrimHandle(unsigned int index);
dvander@229
   186
dvander@229
   187
	/**
dvander@283
   188
	 * Sets the security owner of a type.
dvander@229
   189
	 */
dvander@229
   190
	void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
dvander@229
   191
dvander@283
   192
	/**
dvander@283
   193
	 * Helper function to check access rights.
dvander@229
   194
	 */
dvander@283
   195
	bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
dvander@262
   196
dvander@283
   197
	/** 
dvander@283
   198
	 * Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
dvander@283
   199
	 */
dvander@283
   200
	HandleError FreeHandle(QHandle *pHandle, unsigned int index);
dvander@283
   201
	void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
dvander@283
   202
	HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
dvander@528
   203
	Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity);
dvander@1638
   204
dvander@1638
   205
	bool TryAndFreeSomeHandles();
dvander@1638
   206
	HandleError TryAllocHandle(unsigned int *handle);
dvander@222
   207
private:
dvander@218
   208
	QHandle *m_Handles;
dvander@218
   209
	QHandleType *m_Types;
dvander@218
   210
	Trie *m_TypeLookup;
dvander@218
   211
	unsigned int m_TypeTail;
dvander@218
   212
	unsigned int m_FreeTypes;
dvander@218
   213
	unsigned int m_HandleTail;
dvander@218
   214
	unsigned int m_FreeHandles;
dvander@218
   215
	unsigned int m_HSerial;
dvander@218
   216
	BaseStringTable *m_strtab;
dvander@218
   217
};
dvander@218
   218
dvander@218
   219
extern HandleSystem g_HandleSys;
dvander@218
   220
dvander@218
   221
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_