core/logic/HandleSys.h
author Scott Ehlert <ds@alliedmods.net>
Sun Feb 09 22:50:20 2014 -0600 (2014-02-09)
changeset 4241 46fdb8cd9883
parent 4175 3ae24e84c028
permissions -rw-r--r--
Use == instead of is operator for checking string equality in AMBuild scripts (bug 6043, r=dvander).
dvander@370
     1
/**
dvander@4064
     2
 * vim: set ts=4 sw=4 tw=99 noet :
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@4115
    37
#include <sm_namehashset.h>
dvander@4115
    38
#include <am-string.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@4175
   106
	ke::AutoPtr<ke::AString> name;
dvander@4115
   107
dvander@4115
   108
	static inline bool matches(const char *key, const QHandleType *type)
dvander@4115
   109
	{
dvander@4175
   110
		return type->name && type->name->compare(key) == 0;
dvander@4115
   111
	}
dvander@218
   112
};
dvander@218
   113
dvander@1687
   114
typedef void (HANDLE_REPORTER)(const char *str, ...);
dvander@1687
   115
dvander@218
   116
class HandleSystem : 
dvander@218
   117
	public IHandleSys
dvander@218
   118
{
dvander@229
   119
	friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index);
dvander@229
   120
	friend class ShareSystem;
dvander@218
   121
public:
dvander@218
   122
	HandleSystem();
dvander@218
   123
	~HandleSystem();
dvander@218
   124
public: //IHandleSystem
dvander@262
   125
dvander@262
   126
	HandleType_t CreateType(const char *name,
dvander@262
   127
		IHandleTypeDispatch *dispatch,
dvander@262
   128
		HandleType_t parent,
dvander@262
   129
		const TypeAccess *typeAccess,
dvander@262
   130
		const HandleAccess *hndlAccess,
dvander@262
   131
		IdentityToken_t *ident,
dvander@262
   132
		HandleError *err);
dvander@262
   133
dvander@229
   134
	bool RemoveType(HandleType_t type, IdentityToken_t *ident);
dvander@262
   135
dvander@218
   136
	bool FindHandleType(const char *name, HandleType_t *type);
dvander@262
   137
dvander@218
   138
	Handle_t CreateHandle(HandleType_t type, 
dvander@262
   139
		void *object,
dvander@262
   140
		IdentityToken_t *owner,
dvander@262
   141
		IdentityToken_t *ident,
dvander@262
   142
		HandleError *err);
dvander@283
   143
dvander@262
   144
	HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
dvander@262
   145
dvander@262
   146
	HandleError CloneHandle(Handle_t handle, 
dvander@262
   147
		Handle_t *newhandle, 
dvander@262
   148
		IdentityToken_t *newOwner,
dvander@262
   149
		const HandleSecurity *pSecurity);
dvander@262
   150
dvander@262
   151
	HandleError ReadHandle(Handle_t handle, 
dvander@262
   152
		HandleType_t type, 
dvander@262
   153
		const HandleSecurity *pSecurity,
dvander@262
   154
		void **object);
dvander@262
   155
dvander@262
   156
	bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess);
dvander@262
   157
dvander@229
   158
	bool TypeCheck(HandleType_t intype, HandleType_t outtype);
dvander@528
   159
dvander@528
   160
	virtual Handle_t CreateHandleEx(HandleType_t type, 
dvander@528
   161
		void *object,
dvander@528
   162
		const HandleSecurity *pSec,
dvander@528
   163
		const HandleAccess *pAccess,
dvander@528
   164
		HandleError *err);
dvander@900
   165
dvander@1687
   166
	void Dump(HANDLE_REPORTER rep);
dvander@2959
   167
dvander@2959
   168
	/* Bypasses security checks. */
dvander@2959
   169
	Handle_t FastCloneHandle(Handle_t hndl);
dvander@229
   170
protected:
dvander@222
   171
	/**
dvander@222
   172
	 * Decodes a handle with sanity and security checking.
dvander@222
   173
	 */
dvander@222
   174
	HandleError GetHandle(Handle_t handle, 
dvander@229
   175
						  IdentityToken_t *ident, 
dvander@222
   176
						  QHandle **pHandle, 
dvander@222
   177
						  unsigned int *index,
dvander@259
   178
						  bool ignoreFree=false);
dvander@222
   179
dvander@2959
   180
	Handle_t FastCloneHandle(QHandle *pHandle, unsigned int index);
dvander@2959
   181
	void GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index);
dvander@2959
   182
dvander@222
   183
	/**
dvander@222
   184
	 * Creates a basic handle and sets its reference count to 1.
dvander@222
   185
	 * Does not do any type or security checking.
dvander@222
   186
	 */
dvander@229
   187
	HandleError MakePrimHandle(HandleType_t type, 
dvander@229
   188
							   QHandle **pHandle, 
dvander@229
   189
							   unsigned int *index, 
dvander@229
   190
							   HandleType_t *handle,
dvander@283
   191
							   IdentityToken_t *owner,
dvander@283
   192
							   bool identity=false);
dvander@222
   193
dvander@222
   194
	/**
ds@729
   195
	 * Frees a primitive handle.  Does no object freeing, only reference count, bookkeeping, 
dvander@229
   196
	 * and linked list maintenance.
dvander@283
   197
	 * If used on an Identity handle, destroys all Handles under that identity.
dvander@222
   198
	 */
dvander@222
   199
	void ReleasePrimHandle(unsigned int index);
dvander@229
   200
dvander@229
   201
	/**
dvander@283
   202
	 * Sets the security owner of a type.
dvander@229
   203
	 */
dvander@229
   204
	void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
dvander@229
   205
dvander@283
   206
	/**
dvander@283
   207
	 * Helper function to check access rights.
dvander@229
   208
	 */
dvander@283
   209
	bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
dvander@262
   210
dvander@283
   211
	/** 
dvander@283
   212
	 * Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
dvander@283
   213
	 */
dvander@283
   214
	HandleError FreeHandle(QHandle *pHandle, unsigned int index);
dvander@283
   215
	void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
dvander@283
   216
	HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
dvander@528
   217
	Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity);
dvander@1638
   218
dvander@1638
   219
	bool TryAndFreeSomeHandles();
dvander@1638
   220
	HandleError TryAllocHandle(unsigned int *handle);
dvander@222
   221
private:
dvander@218
   222
	QHandle *m_Handles;
dvander@218
   223
	QHandleType *m_Types;
dvander@4115
   224
	NameHashSet<QHandleType *> m_TypeLookup;
dvander@218
   225
	unsigned int m_TypeTail;
dvander@218
   226
	unsigned int m_FreeTypes;
dvander@218
   227
	unsigned int m_HandleTail;
dvander@218
   228
	unsigned int m_FreeHandles;
dvander@218
   229
	unsigned int m_HSerial;
dvander@218
   230
};
dvander@218
   231
dvander@218
   232
extern HandleSystem g_HandleSys;
dvander@218
   233
dvander@2959
   234
struct AutoHandleRooter
dvander@2959
   235
{
dvander@2959
   236
public:
dvander@2959
   237
	AutoHandleRooter(Handle_t hndl)
dvander@2959
   238
	{
dvander@2959
   239
		if (hndl != BAD_HANDLE)
dvander@2959
   240
			this->hndl = g_HandleSys.FastCloneHandle(hndl);
dvander@2959
   241
		else
dvander@2959
   242
			this->hndl = BAD_HANDLE;
dvander@2959
   243
	}
dvander@2959
   244
dvander@2959
   245
	~AutoHandleRooter()
dvander@2959
   246
	{
dvander@2959
   247
		if (hndl != BAD_HANDLE)
dvander@2959
   248
		{
dvander@2959
   249
			HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
dvander@2959
   250
			g_HandleSys.FreeHandle(hndl, &sec);
dvander@2959
   251
		}
dvander@2959
   252
	}
dvander@2959
   253
private:
dvander@2959
   254
	Handle_t hndl;
dvander@2959
   255
};
dvander@2959
   256
dvander@218
   257
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_