core/logic/HandleSys.h
author Kyle Sanderson <kyle.leet@gmail.com>
Thu Jul 18 15:50:50 2013 -0400 (2013-07-18)
changeset 3950 d467a6526f8d
parent 3872 4c93f74cae51
child 4064 d7ca1e28949d
permissions -rw-r--r--
Fixed accidental assignment in each of SDKTools and sp compiler (bug 5745, r=psychonic).
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 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@3872
    37
#include <sm_trie_tpl.h>
dvander@218
    38
#include "sm_memtable.h"
dvander@3872
    39
#include "common_logic.h"
dvander@218
    40
dvander@222
    41
#define HANDLESYS_MAX_HANDLES		(1<<14)
dvander@218
    42
#define HANDLESYS_MAX_TYPES			(1<<9)
dvander@218
    43
#define HANDLESYS_MAX_SUBTYPES		0xF
dvander@218
    44
#define HANDLESYS_SUBTYPE_MASK		0xF
dvander@218
    45
#define HANDLESYS_TYPEARRAY_SIZE	(HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
dvander@218
    46
#define HANDLESYS_MAX_SERIALS		0xFFFF
dvander@218
    47
#define HANDLESYS_SERIAL_MASK		0xFFFF0000
dvander@218
    48
#define HANDLESYS_HANDLE_MASK		0x0000FFFF
dvander@218
    49
dvander@1766
    50
#define HANDLESYS_MEMUSAGE_MIN_VERSION		3
dvander@1766
    51
dvander@229
    52
/**
dvander@229
    53
 *   The QHandle is a nasty structure that compacts the handle system into a big vector.
dvander@229
    54
 * The members of the vector each encapsulate one Handle, however, they also act as nodes
dvander@229
    55
 * in an inlined linked list and an inlined vector.
dvander@229
    56
 *
dvander@229
    57
 *   The first of these lists is the 'freeID' list.  Each node from 1 to N (where N
dvander@229
    58
 * is the number of free nodes) has a 'freeID' that specifies a free Handle ID.  This
dvander@229
    59
 * is a quick hack to get around allocating a second base vector.
dvander@229
    60
 *
dvander@229
    61
 *   The second vector is the identity linked list.  An identity has its own handle, so
dvander@229
    62
 * these handles are used as sentinel nodes for index linking.  They point to the first and last
ds@487
    63
 * index into the handle array.  Each subsequent Handle who is owned by that identity is mapped into
dvander@229
    64
 * that list.  This lets owning identities be unloaded in O(n) time.
dvander@229
    65
 *
dvander@229
    66
 *   Eventually, there may be a third list for type chains.
dvander@229
    67
 */
dvander@229
    68
dvander@229
    69
enum HandleSet
dvander@229
    70
{
dvander@229
    71
	HandleSet_None = 0,
dvander@259
    72
	HandleSet_Used,			/* The Handle is in use */
dvander@259
    73
	HandleSet_Freed,		/* The "master" Handle of a clone chain is freed */
dvander@259
    74
	HandleSet_Identity,		/* The Handle is a special identity */
dvander@229
    75
};
dvander@229
    76
dvander@218
    77
struct QHandle
dvander@218
    78
{
dvander@222
    79
	HandleType_t type;			/* Handle type */
dvander@222
    80
	void *object;				/* Unmaintained object pointer */
dvander@229
    81
	IdentityToken_t *owner;		/* Identity of object which owns this */
dvander@222
    82
	unsigned int serial;		/* Serial no. for sanity checking */
dvander@222
    83
	unsigned int refcount;		/* Reference count for safe destruction */
dvander@262
    84
	unsigned int clone;			/* If non-zero, this is our cloned parent index */
dvander@229
    85
	HandleSet set;				/* Information about the handle's state */
dvander@528
    86
	bool access_special;		/* Whether or not access rules are special or type-derived */
dvander@789
    87
	bool is_destroying;			/* Whether or not the handle is being destroyed */
dvander@528
    88
	HandleAccess sec;			/* Security rules */
dvander@229
    89
	/* The following variables are unrelated to the Handle array, and used 
dvander@229
    90
	 * as an inlined chain of information */
dvander@229
    91
	unsigned int freeID;		/* ID of a free handle in the free handle chain */
dvander@229
    92
	/* Indexes into the handle array for owner membership.
dvander@229
    93
	 * For identity roots, these are treated as the head/tail. */
dvander@283
    94
	unsigned int ch_prev;		/* chained previous handle */
dvander@283
    95
	unsigned int ch_next;		/* chained next handle */
dvander@218
    96
};
dvander@218
    97
dvander@218
    98
struct QHandleType
dvander@218
    99
{
dvander@218
   100
	IHandleTypeDispatch *dispatch;
dvander@218
   101
	unsigned int freeID;
dvander@218
   102
	unsigned int children;
dvander@262
   103
	TypeAccess typeSec;
dvander@262
   104
	HandleAccess hndlSec;
dvander@218
   105
	unsigned int opened;
dvander@218
   106
	int nameIdx;
dvander@218
   107
};
dvander@218
   108
dvander@1687
   109
typedef void (HANDLE_REPORTER)(const char *str, ...);
dvander@1687
   110
dvander@218
   111
class HandleSystem : 
dvander@218
   112
	public IHandleSys
dvander@218
   113
{
dvander@229
   114
	friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index);
dvander@229
   115
	friend class ShareSystem;
dvander@218
   116
public:
dvander@218
   117
	HandleSystem();
dvander@218
   118
	~HandleSystem();
dvander@218
   119
public: //IHandleSystem
dvander@262
   120
dvander@262
   121
	HandleType_t CreateType(const char *name,
dvander@262
   122
		IHandleTypeDispatch *dispatch,
dvander@262
   123
		HandleType_t parent,
dvander@262
   124
		const TypeAccess *typeAccess,
dvander@262
   125
		const HandleAccess *hndlAccess,
dvander@262
   126
		IdentityToken_t *ident,
dvander@262
   127
		HandleError *err);
dvander@262
   128
dvander@229
   129
	bool RemoveType(HandleType_t type, IdentityToken_t *ident);
dvander@262
   130
dvander@218
   131
	bool FindHandleType(const char *name, HandleType_t *type);
dvander@262
   132
dvander@218
   133
	Handle_t CreateHandle(HandleType_t type, 
dvander@262
   134
		void *object,
dvander@262
   135
		IdentityToken_t *owner,
dvander@262
   136
		IdentityToken_t *ident,
dvander@262
   137
		HandleError *err);
dvander@283
   138
dvander@262
   139
	HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
dvander@262
   140
dvander@262
   141
	HandleError CloneHandle(Handle_t handle, 
dvander@262
   142
		Handle_t *newhandle, 
dvander@262
   143
		IdentityToken_t *newOwner,
dvander@262
   144
		const HandleSecurity *pSecurity);
dvander@262
   145
dvander@262
   146
	HandleError ReadHandle(Handle_t handle, 
dvander@262
   147
		HandleType_t type, 
dvander@262
   148
		const HandleSecurity *pSecurity,
dvander@262
   149
		void **object);
dvander@262
   150
dvander@262
   151
	bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess);
dvander@262
   152
dvander@229
   153
	bool TypeCheck(HandleType_t intype, HandleType_t outtype);
dvander@528
   154
dvander@528
   155
	virtual Handle_t CreateHandleEx(HandleType_t type, 
dvander@528
   156
		void *object,
dvander@528
   157
		const HandleSecurity *pSec,
dvander@528
   158
		const HandleAccess *pAccess,
dvander@528
   159
		HandleError *err);
dvander@900
   160
dvander@1687
   161
	void Dump(HANDLE_REPORTER rep);
dvander@2959
   162
dvander@2959
   163
	/* Bypasses security checks. */
dvander@2959
   164
	Handle_t FastCloneHandle(Handle_t hndl);
dvander@229
   165
protected:
dvander@222
   166
	/**
dvander@222
   167
	 * Decodes a handle with sanity and security checking.
dvander@222
   168
	 */
dvander@222
   169
	HandleError GetHandle(Handle_t handle, 
dvander@229
   170
						  IdentityToken_t *ident, 
dvander@222
   171
						  QHandle **pHandle, 
dvander@222
   172
						  unsigned int *index,
dvander@259
   173
						  bool ignoreFree=false);
dvander@222
   174
dvander@2959
   175
	Handle_t FastCloneHandle(QHandle *pHandle, unsigned int index);
dvander@2959
   176
	void GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index);
dvander@2959
   177
dvander@222
   178
	/**
dvander@222
   179
	 * Creates a basic handle and sets its reference count to 1.
dvander@222
   180
	 * Does not do any type or security checking.
dvander@222
   181
	 */
dvander@229
   182
	HandleError MakePrimHandle(HandleType_t type, 
dvander@229
   183
							   QHandle **pHandle, 
dvander@229
   184
							   unsigned int *index, 
dvander@229
   185
							   HandleType_t *handle,
dvander@283
   186
							   IdentityToken_t *owner,
dvander@283
   187
							   bool identity=false);
dvander@222
   188
dvander@222
   189
	/**
ds@729
   190
	 * Frees a primitive handle.  Does no object freeing, only reference count, bookkeeping, 
dvander@229
   191
	 * and linked list maintenance.
dvander@283
   192
	 * If used on an Identity handle, destroys all Handles under that identity.
dvander@222
   193
	 */
dvander@222
   194
	void ReleasePrimHandle(unsigned int index);
dvander@229
   195
dvander@229
   196
	/**
dvander@283
   197
	 * Sets the security owner of a type.
dvander@229
   198
	 */
dvander@229
   199
	void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
dvander@229
   200
dvander@283
   201
	/**
dvander@283
   202
	 * Helper function to check access rights.
dvander@229
   203
	 */
dvander@283
   204
	bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
dvander@262
   205
dvander@283
   206
	/** 
dvander@283
   207
	 * Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
dvander@283
   208
	 */
dvander@283
   209
	HandleError FreeHandle(QHandle *pHandle, unsigned int index);
dvander@283
   210
	void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
dvander@283
   211
	HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
dvander@528
   212
	Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity);
dvander@1638
   213
dvander@1638
   214
	bool TryAndFreeSomeHandles();
dvander@1638
   215
	HandleError TryAllocHandle(unsigned int *handle);
dvander@222
   216
private:
dvander@218
   217
	QHandle *m_Handles;
dvander@218
   218
	QHandleType *m_Types;
dvander@3872
   219
	KTrie<QHandleType *> m_TypeLookup;
dvander@218
   220
	unsigned int m_TypeTail;
dvander@218
   221
	unsigned int m_FreeTypes;
dvander@218
   222
	unsigned int m_HandleTail;
dvander@218
   223
	unsigned int m_FreeHandles;
dvander@218
   224
	unsigned int m_HSerial;
dvander@218
   225
	BaseStringTable *m_strtab;
dvander@218
   226
};
dvander@218
   227
dvander@218
   228
extern HandleSystem g_HandleSys;
dvander@218
   229
dvander@2959
   230
struct AutoHandleRooter
dvander@2959
   231
{
dvander@2959
   232
public:
dvander@2959
   233
	AutoHandleRooter(Handle_t hndl)
dvander@2959
   234
	{
dvander@2959
   235
		if (hndl != BAD_HANDLE)
dvander@2959
   236
			this->hndl = g_HandleSys.FastCloneHandle(hndl);
dvander@2959
   237
		else
dvander@2959
   238
			this->hndl = BAD_HANDLE;
dvander@2959
   239
	}
dvander@2959
   240
dvander@2959
   241
	~AutoHandleRooter()
dvander@2959
   242
	{
dvander@2959
   243
		if (hndl != BAD_HANDLE)
dvander@2959
   244
		{
dvander@2959
   245
			HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
dvander@2959
   246
			g_HandleSys.FreeHandle(hndl, &sec);
dvander@2959
   247
		}
dvander@2959
   248
	}
dvander@2959
   249
private:
dvander@2959
   250
	Handle_t hndl;
dvander@2959
   251
};
dvander@2959
   252
dvander@218
   253
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_