diff options
Diffstat (limited to 'drivers/gpu/pvr/services4/srvkm/common/handle.c')
| -rw-r--r-- | drivers/gpu/pvr/services4/srvkm/common/handle.c | 2689 | 
1 files changed, 2689 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/services4/srvkm/common/handle.c b/drivers/gpu/pvr/services4/srvkm/common/handle.c new file mode 100644 index 00000000000..1e260470e7e --- /dev/null +++ b/drivers/gpu/pvr/services4/srvkm/common/handle.c @@ -0,0 +1,2689 @@ +/*************************************************************************/ /*! +@Title          Resource Handle Manager +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    Provide resource handle management +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) +/* See handle.h for a description of the handle API. */ + +/* + * There is no locking here.  It is assumed the code is used in a single + * threaded environment.  In particular, it is assumed that the code will + * never be called from an interrupt handler. + * + * The implmentation supports movable handle structures, allowing the address + * of a handle structure to change without having to fix up pointers in + * any of the handle structures.  For example, the linked list mechanism + * used to link subhandles together uses handle array indices rather than + * pointers to the structures themselves. + */ + +#include <stddef.h> + +#include "services_headers.h" +#include "handle.h" + +#ifdef	DEBUG +#define	HANDLE_BLOCK_SHIFT	2 +#else +#define	HANDLE_BLOCK_SHIFT	8 +#endif + +#define	DIVIDE_BY_BLOCK_SIZE(i)		(((IMG_UINT32)(i)) >> HANDLE_BLOCK_SHIFT) +#define	MULTIPLY_BY_BLOCK_SIZE(i)	(((IMG_UINT32)(i)) << HANDLE_BLOCK_SHIFT) + +#define HANDLE_BLOCK_SIZE       MULTIPLY_BY_BLOCK_SIZE(1) +#define	HANDLE_SUB_BLOCK_MASK	(HANDLE_BLOCK_SIZE - 1) +#define	HANDLE_BLOCK_MASK	(~(HANDLE_SUB_BLOCK_MASK)) + +#define	HANDLE_HASH_TAB_INIT_SIZE	32 + +#define	INDEX_IS_VALID(psBase, i) ((i) < (psBase)->ui32TotalHandCount) + +/* Valid handles are never NULL, but handle array indices are based from 0 */ +#if defined (SUPPORT_SID_INTERFACE) +#define	INDEX_TO_HANDLE(i) ((IMG_SID)((i) + 1)) +#define	HANDLE_TO_INDEX(h) ((IMG_UINT32)(h) - 1) +#else +#define	INDEX_TO_HANDLE(i) ((IMG_HANDLE)((IMG_UINTPTR_T)(i) + 1)) +#define	HANDLE_TO_INDEX(h) ((IMG_UINT32)(IMG_UINTPTR_T)(h) - 1) + +#endif + +#define	INDEX_TO_BLOCK_INDEX(i)		DIVIDE_BY_BLOCK_SIZE(i) +#define BLOCK_INDEX_TO_INDEX(i)		MULTIPLY_BY_BLOCK_SIZE(i) +#define INDEX_TO_SUB_BLOCK_INDEX(i)	((i) & HANDLE_SUB_BLOCK_MASK) + +#define INDEX_TO_INDEX_STRUCT_PTR(psArray, i) (&((psArray)[INDEX_TO_BLOCK_INDEX(i)])) +#define	BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, i) INDEX_TO_INDEX_STRUCT_PTR((psBase)->psHandleArray, i) + +#define	INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, i) (BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, i)->ui32FreeHandBlockCount) + +#define INDEX_TO_HANDLE_STRUCT_PTR(psBase, i) (BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, i)->psHandle + INDEX_TO_SUB_BLOCK_INDEX(i)) + +#define	HANDLE_TO_HANDLE_STRUCT_PTR(psBase, h) (INDEX_TO_HANDLE_STRUCT_PTR(psBase, HANDLE_TO_INDEX(h))) + +#define	HANDLE_PTR_TO_INDEX(psHandle) ((psHandle)->ui32Index) +#define	HANDLE_PTR_TO_HANDLE(psHandle) INDEX_TO_HANDLE(HANDLE_PTR_TO_INDEX(psHandle)) + +#define	ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(a) (HANDLE_BLOCK_MASK & (a)) +#define	ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(a) ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE((a) + HANDLE_BLOCK_SIZE - 1) + +#define	DEFAULT_MAX_HANDLE		0x7fffffffu +#define	DEFAULT_MAX_INDEX_PLUS_ONE	ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(DEFAULT_MAX_HANDLE) + +#define	HANDLES_BATCHED(psBase) ((psBase)->ui32HandBatchSize != 0) + +#define HANDLE_ARRAY_SIZE(handleCount) DIVIDE_BY_BLOCK_SIZE(ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(handleCount)) + +#define	SET_FLAG(v, f) ((IMG_VOID)((v) |= (f))) +#define	CLEAR_FLAG(v, f) ((IMG_VOID)((v) &= ~(f))) +#define	TEST_FLAG(v, f) ((IMG_BOOL)(((v) & (f)) != 0)) + +#define	TEST_ALLOC_FLAG(psHandle, f) TEST_FLAG((psHandle)->eFlag, f) + +#define	SET_INTERNAL_FLAG(psHandle, f) SET_FLAG((psHandle)->eInternalFlag, f) +#define	CLEAR_INTERNAL_FLAG(psHandle, f) CLEAR_FLAG((psHandle)->eInternalFlag, f) +#define	TEST_INTERNAL_FLAG(psHandle, f) TEST_FLAG((psHandle)->eInternalFlag, f) + +#define	BATCHED_HANDLE(psHandle) TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED) + +#define	SET_BATCHED_HANDLE(psHandle) SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED) + +#define	SET_UNBATCHED_HANDLE(psHandle) CLEAR_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED) + +#define	BATCHED_HANDLE_PARTIALLY_FREE(psHandle) TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE) + +#define SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle) SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE) + +#define	HANDLE_STRUCT_IS_FREE(psHandle) ((psHandle)->eType == PVRSRV_HANDLE_TYPE_NONE && (psHandle)->eInternalFlag == INTERNAL_HANDLE_FLAG_NONE) + +#ifdef	MIN +#undef MIN +#endif + +#define	MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/* + * Linked list structure.  Used for both the list head and list items. + * Array indices, rather than pointers, are used to point to the next and + * previous items on the list. + */ +struct sHandleList +{ +	IMG_UINT32 ui32Prev; +	IMG_UINT32 ui32Next; +#if defined (SUPPORT_SID_INTERFACE) +	IMG_SID hParent; +#else +	IMG_HANDLE hParent; +#endif +}; + +enum ePVRSRVInternalHandleFlag +{ +	INTERNAL_HANDLE_FLAG_NONE = 0x00, +	INTERNAL_HANDLE_FLAG_BATCHED = 0x01, +	INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE = 0x02, +}; + +/* Handle structure */ +struct sHandle +{ +	/* Handle type */ +	PVRSRV_HANDLE_TYPE eType; + +	/* Pointer to the data that the handle represents */ +	IMG_VOID *pvData; + +	/* +	 * When handles are on the free list, the value of the "next index +	 * plus one field" has the following meaning: +	 * zero - next handle is the one that follows this one, +	 * nonzero - the index of the next handle is the value minus one. +	 * This scheme means handle space can be initialised to all zeros. +	 * +	 * When this field is used to link together handles on a list +	 * other than the free list, zero indicates the end of the +	 * list, with nonzero the same as above. +	 */ +	IMG_UINT32 ui32NextIndexPlusOne; + +	/* Internal flags */ +	enum ePVRSRVInternalHandleFlag eInternalFlag; + +	/* Flags specified when the handle was allocated */ +	PVRSRV_HANDLE_ALLOC_FLAG eFlag; + +	/* Index of this handle in the handle array */ +	IMG_UINT32 ui32Index; + +	/* List head for subhandles of this handle */ +	struct sHandleList sChildren; + +	/* List entry for sibling subhandles */ +	struct sHandleList sSiblings; +}; + +/* Handle array index structure. + * The handle array is an array of index structures, reallocated as the number of + * handles increases. + * NOTE: There is one index structure per block of handles. + */ +struct sHandleIndex +{ +	/* Pointer to first handle structure in the block */ +	struct sHandle *psHandle; + +	/* Block allocation cookie returned from OSAllocMem for the block of handles */ +	IMG_HANDLE hBlockAlloc; + +	/* Number of free handles in block */ +	IMG_UINT32 ui32FreeHandBlockCount; +}; + +struct _PVRSRV_HANDLE_BASE_ +{ +	/*  Handle returned from OSAllocMem for handle base allocation */ +	IMG_HANDLE hBaseBlockAlloc; + +	/* Handle returned from OSAllocMem for handle array allocation */ +	IMG_HANDLE hArrayBlockAlloc; + +	/* Pointer to array of pointers to handle structures */ +	struct sHandleIndex *psHandleArray; + +	/* +	 * Pointer to handle hash table. +	 * The hash table is used to do reverse lookups, converting data +	 * pointers to handles. +	 */ +	HASH_TABLE *psHashTab; + +	/* Number of free handles */ +	IMG_UINT32 ui32FreeHandCount; + +	/* +	 * If purging is not enabled, this is the array index of first free +	 * handle. +	 * If purging is enabled, this is the index to start searching for +	 * a free handle from.  In this case it is usually zero, unless +	 * the handle array size has been increased due to lack of +	 * handles. +	 */ +	IMG_UINT32 ui32FirstFreeIndex; + +	/* Maximum handle index, plus one */ +	IMG_UINT32 ui32MaxIndexPlusOne; + +	/* Total number of handles, free and allocated */ +	IMG_UINT32 ui32TotalHandCount; + +	/* +	 * Index of the last free index, plus one. Not used if purging +	 * is enabled. +	 */ +	IMG_UINT32 ui32LastFreeIndexPlusOne; + +	/* Size of current handle batch, or zero if batching not enabled */ +	IMG_UINT32 ui32HandBatchSize; + +	/* Number of handles prior to start of current batch */ +	IMG_UINT32 ui32TotalHandCountPreBatch; + +	/* Index of first handle in batch, plus one */ +	IMG_UINT32 ui32FirstBatchIndexPlusOne; + +	/* Number of handle allocation failures in batch */ +	IMG_UINT32 ui32BatchHandAllocFailures; + +	/* Purging enabled. +	 * If purging is enabled, the size of the table can be reduced +	 * by removing free space at the end of the table.  To make +	 * purging more likely to succeed, handles are allocated as +	 * far to the front of the table as possible.  The first free +	 * handle is found by a linear search from the start of the table, +	 * and so no free handle list management is done. +	 */ +	IMG_BOOL bPurgingEnabled; +}; + +/* + * The key for the handle hash table is an array of three elements, the + * pointer to the resource, the resource type, and the process ID.  The + * eHandKey enumeration gives the array indices of the elements making + * up the key. + */ +enum eHandKey { +	HAND_KEY_DATA = 0, +	HAND_KEY_TYPE, +	HAND_KEY_PARENT, +	HAND_KEY_LEN			/* Must be last item in list */ +}; + +/* + * Kernel handle base structure.  For handles that are not allocated on + * behalf of a particular process + */ +PVRSRV_HANDLE_BASE *gpsKernelHandleBase = IMG_NULL; + +/* HAND_KEY is the type of the hash table key */ +typedef IMG_UINTPTR_T HAND_KEY[HAND_KEY_LEN]; + +/*! +****************************************************************************** + + @Function	HandleListInit + + @Description	Initialise a linked list structure embedded in a handle +		structure. + + @Input		ui32Index - index of handle in the handle array +		psList - pointer to linked list structure +		hParent - parent handle, or IMG_NULL + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(HandleListInit) +#endif +static INLINE +#if defined (SUPPORT_SID_INTERFACE) +IMG_VOID HandleListInit(IMG_UINT32 ui32Index, struct sHandleList *psList, IMG_SID hParent) +#else +IMG_VOID HandleListInit(IMG_UINT32 ui32Index, struct sHandleList *psList, IMG_HANDLE hParent) +#endif +{ +	psList->ui32Next = ui32Index; +	psList->ui32Prev = ui32Index; +	psList->hParent = hParent; +} + +/*! +****************************************************************************** + + @Function	InitParentList + + @Description	Initialise the children list head in a handle structure. +		The children are the subhandles of this handle. + + @Input		psHandle - pointer to handle structure + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(InitParentList) +#endif +static INLINE +IMG_VOID InitParentList(struct sHandle *psHandle) +{ +	IMG_UINT32 ui32Parent = HANDLE_PTR_TO_INDEX(psHandle); + +	HandleListInit(ui32Parent, &psHandle->sChildren, INDEX_TO_HANDLE(ui32Parent)); +} + +/*! +****************************************************************************** + + @Function	InitChildEntry + + @Description	Initialise the child list entry in a handle structure. +		The list entry is used to link together subhandles of +		a given handle. + + @Input		psHandle - pointer to handle structure + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(InitChildEntry) +#endif +static INLINE +IMG_VOID InitChildEntry(struct sHandle *psHandle) +{ +	HandleListInit(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings, IMG_NULL); +} + +/*! +****************************************************************************** + + @Function	HandleListIsEmpty + + @Description	Determine whether a given linked list is empty. + + @Input		ui32Index - index of the handle containing the list head +		psList - pointer to the list head + + @Return	IMG_TRUE if the list is empty, IMG_FALSE if it isn't. + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(HandleListIsEmpty) +#endif +static INLINE +IMG_BOOL HandleListIsEmpty(IMG_UINT32 ui32Index, struct sHandleList *psList) +{ +	IMG_BOOL bIsEmpty; + +	bIsEmpty = (IMG_BOOL)(psList->ui32Next == ui32Index); + +#ifdef	DEBUG +	{ +		IMG_BOOL bIsEmpty2; + +		bIsEmpty2 = (IMG_BOOL)(psList->ui32Prev == ui32Index); +		PVR_ASSERT(bIsEmpty == bIsEmpty2); +	} +#endif + +	return bIsEmpty; +} + +#ifdef DEBUG +/*! +****************************************************************************** + + @Function	NoChildren + + @Description	Determine whether a handle has any subhandles + + @Input		psHandle - pointer to handle structure + + @Return	IMG_TRUE if the handle has no subhandles, IMG_FALSE if it does. + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(NoChildren) +#endif +static INLINE +IMG_BOOL NoChildren(struct sHandle *psHandle) +{ +	PVR_ASSERT(psHandle->sChildren.hParent == HANDLE_PTR_TO_HANDLE(psHandle)); + +	return HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sChildren); +} + +/*! +****************************************************************************** + + @Function	NoParent + + @Description	Determine whether a handle is a subhandle + + @Input		psHandle - pointer to handle structure + + @Return	IMG_TRUE if the handle is not a subhandle, IMG_FALSE if it is. + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(NoParent) +#endif +static INLINE +IMG_BOOL NoParent(struct sHandle *psHandle) +{ +	if (HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings)) +	{ +		PVR_ASSERT(psHandle->sSiblings.hParent == IMG_NULL); + +		return IMG_TRUE; +	} +	else +	{ +		PVR_ASSERT(psHandle->sSiblings.hParent != IMG_NULL); +	} +	return IMG_FALSE; +} +#endif /*DEBUG*/ +/*! +****************************************************************************** + + @Function	ParentHandle + + @Description	Determine the parent of a handle + + @Input		psHandle - pointer to handle structure + + @Return	Parent handle, or IMG_NULL if the handle is not a subhandle. + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(ParentHandle) +#endif +static INLINE +#if defined (SUPPORT_SID_INTERFACE) +IMG_SID ParentHandle(struct sHandle *psHandle) +#else +IMG_HANDLE ParentHandle(struct sHandle *psHandle) +#endif +{ +	return psHandle->sSiblings.hParent; +} + +/* + * The LIST_PTR_FROM_INDEX_AND_OFFSET macro is used to generate either a + * pointer to the subhandle list head, or a pointer to the linked list + * structure of an item on a subhandle list. + * The list head is itself on the list, but is at a different offset + * in the handle structure to the linked list structure for items on + * the list.  The two linked list structures are differentiated by + * the third parameter, containing the parent index.  The parent field + * in the list head structure references the handle structure that contains + * it.  For items on the list, the parent field in the linked list structure + * references the parent handle, which will be different from the handle + * containing the linked list structure. + */ +#define	LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, i, p, po, eo) \ +		((struct sHandleList *)((IMG_CHAR *)(INDEX_TO_HANDLE_STRUCT_PTR(psBase, i)) + (((i) == (p)) ? (po) : (eo)))) + +/*! +****************************************************************************** + + @Function	HandleListInsertBefore + + @Description	Insert a handle before a handle currently on the list. + + @Input		ui32InsIndex - index of handle to be inserted after +		psIns - pointer to handle structure to be inserted after +		uiParentOffset - offset to list head struct in handle structure +		ui32EntryIndex - index of handle to be inserted +		psEntry - pointer to handle structure of item to be inserted +		uiEntryOffset - offset of list item struct in handle structure + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(HandleListInsertBefore) +#endif +static INLINE +IMG_VOID HandleListInsertBefore(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32InsIndex, struct sHandleList *psIns, IMG_SIZE_T uiParentOffset, IMG_UINT32 ui32EntryIndex, struct sHandleList *psEntry, IMG_SIZE_T uiEntryOffset, IMG_UINT32 ui32ParentIndex) +{ +	/* PRQA S 3305 7 */ /*override stricter alignment warning */ +	struct sHandleList *psPrevIns = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psIns->ui32Prev, ui32ParentIndex, uiParentOffset, uiEntryOffset); + +	PVR_ASSERT(psEntry->hParent == IMG_NULL); +	PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next); +	PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset, uiParentOffset)->hParent == INDEX_TO_HANDLE(ui32ParentIndex)); + +	psEntry->ui32Prev = psIns->ui32Prev; +	psIns->ui32Prev = ui32EntryIndex; +	psEntry->ui32Next = ui32InsIndex; +	psPrevIns->ui32Next = ui32EntryIndex; + +	psEntry->hParent = INDEX_TO_HANDLE(ui32ParentIndex); +} + +/*! +****************************************************************************** + + @Function	AdoptChild + + @Description	Assign a subhandle to a handle + + @Input		psParent - pointer to handle structure of parent handle +		psChild - pointer to handle structure of child subhandle + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(AdoptChild) +#endif +static INLINE +IMG_VOID AdoptChild(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, struct sHandle *psChild) +{ +	IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psParent->sChildren.hParent); + +	PVR_ASSERT(ui32Parent == HANDLE_PTR_TO_INDEX(psParent)); + +	HandleListInsertBefore(psBase, ui32Parent, &psParent->sChildren, offsetof(struct sHandle, sChildren), HANDLE_PTR_TO_INDEX(psChild), &psChild->sSiblings, offsetof(struct sHandle, sSiblings), ui32Parent); + +} + +/*! +****************************************************************************** + + @Function	HandleListRemove + + @Description	Remove a handle from a list + + @Input		ui32EntryIndex - index of handle to be removed +		psEntry - pointer to handle structure of item to be removed +		uiEntryOffset - offset of list item struct in handle structure +		uiParentOffset - offset to list head struct in handle structure + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(HandleListRemove) +#endif +static INLINE +IMG_VOID HandleListRemove(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32EntryIndex, struct sHandleList *psEntry, IMG_SIZE_T uiEntryOffset, IMG_SIZE_T uiParentOffset) +{ +	if (!HandleListIsEmpty(ui32EntryIndex, psEntry)) +	{ +		/* PRQA S 3305 3 */ /*override stricter alignment warning */ +		struct sHandleList *psPrev = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Prev, HANDLE_TO_INDEX(psEntry->hParent), uiParentOffset, uiEntryOffset); +		struct sHandleList *psNext = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Next, HANDLE_TO_INDEX(psEntry->hParent), uiParentOffset, uiEntryOffset); + +		/* +		 * The list head is on the list, and we don't want to +		 * remove it. +		 */ +		PVR_ASSERT(psEntry->hParent != IMG_NULL); + +		psPrev->ui32Next = psEntry->ui32Next; +		psNext->ui32Prev = psEntry->ui32Prev; + +		HandleListInit(ui32EntryIndex, psEntry, IMG_NULL); +	} +} + +/*! +****************************************************************************** + + @Function	UnlinkFromParent + + @Description	Remove a subhandle from its parents list + + @Input		psHandle - pointer to handle structure of child subhandle + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(UnlinkFromParent) +#endif +static INLINE +IMG_VOID UnlinkFromParent(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle) +{ +	HandleListRemove(psBase, HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings, offsetof(struct sHandle, sSiblings), offsetof(struct sHandle, sChildren)); +} + +/*! +****************************************************************************** + + @Function	HandleListIterate + + @Description	Iterate over the items in a list + + @Input		psHead - pointer to list head +		uiParentOffset - offset to list head struct in handle structure +		uiEntryOffset - offset of list item struct in handle structure +		pfnIterFunc - function to be called for each handle in the list + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(HandleListIterate) +#endif +static INLINE +PVRSRV_ERROR HandleListIterate(PVRSRV_HANDLE_BASE *psBase, struct sHandleList *psHead, IMG_SIZE_T uiParentOffset, IMG_SIZE_T uiEntryOffset, PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, struct sHandle *)) +{ +	IMG_UINT32 ui32Index; +	IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psHead->hParent); + +	PVR_ASSERT(psHead->hParent != IMG_NULL); + +	/* + 	 * Follow the next chain from the list head until we reach + 	 * the list head again, which signifies the end of the list. + 	 */ +	for(ui32Index = psHead->ui32Next; ui32Index != ui32Parent; ) +	{ +		struct sHandle *psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32Index); +		/* PRQA S 3305 2 */ /*override stricter alignment warning */ +		struct sHandleList *psEntry = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32Index, ui32Parent, uiParentOffset, uiEntryOffset); +		PVRSRV_ERROR eError; + +		PVR_ASSERT(psEntry->hParent == psHead->hParent); +		/* +		 * Get the next index now, in case the list item is +		 * modified by the iteration function. +		 */ +		ui32Index = psEntry->ui32Next; + +		eError = (*pfnIterFunc)(psBase, psHandle); +		if (eError != PVRSRV_OK) +		{ +			return eError; +		} +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	IterateOverChildren + + @Description	Iterate over the subhandles of a parent handle + + @Input		psParent - pointer to parent handle structure +		pfnIterFunc - function to be called for each subhandle + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(IterateOverChildren) +#endif +static INLINE +PVRSRV_ERROR IterateOverChildren(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, struct sHandle *)) +{ +	 return HandleListIterate(psBase, &psParent->sChildren, offsetof(struct sHandle, sChildren), offsetof(struct sHandle, sSiblings), pfnIterFunc); +} + +/*! +****************************************************************************** + + @Function	GetHandleStructure + + @Description	Get the handle structure for a given handle + + @Input		psBase - pointer to handle base structure +		ppsHandle - location to return pointer to handle structure +		hHandle - handle from client +		eType - handle type or PVRSRV_HANDLE_TYPE_NONE if the +			handle type is not to be checked. + + @Output	ppsHandle - points to a pointer to the handle structure + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(GetHandleStructure) +#endif +static INLINE +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **ppsHandle, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) +#else +PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **ppsHandle, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType) +#endif +{ +	IMG_UINT32 ui32Index = HANDLE_TO_INDEX(hHandle); +	struct sHandle *psHandle; + +	/* Check handle index is in range */ +	if (!INDEX_IS_VALID(psBase, ui32Index)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle index out of range (%u >= %u)", ui32Index, psBase->ui32TotalHandCount)); +#if defined (SUPPORT_SID_INTERFACE) +		PVR_DBG_BREAK +#endif +		return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE; +	} + +	psHandle =  INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32Index); +	if (psHandle->eType == PVRSRV_HANDLE_TYPE_NONE) +	{ +		PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle not allocated (index: %u)", ui32Index)); +#if defined (SUPPORT_SID_INTERFACE) +		PVR_DBG_BREAK +#endif +		return PVRSRV_ERROR_HANDLE_NOT_ALLOCATED; +	} + +	/* +	 * Unless PVRSRV_HANDLE_TYPE_NONE was passed in to this function, +	 * check handle is of the correct type. +	 */ +	if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandle->eType) +	{ +		PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle type mismatch (%d != %d)", eType, psHandle->eType)); +#if defined (SUPPORT_SID_INTERFACE) +		PVR_DBG_BREAK +#endif +		return PVRSRV_ERROR_HANDLE_TYPE_MISMATCH; +	} + +	/* Return the handle structure */ +	*ppsHandle = psHandle; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	ParentIfPrivate + + @Description	Return the parent handle if the handle was allocated +		with PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE, else return +		IMG_NULL + + @Input		psHandle - pointer to handle + + @Return	Parent handle, or IMG_NULL + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(ParentIfPrivate) +#endif +static INLINE +#if defined (SUPPORT_SID_INTERFACE) +IMG_SID ParentIfPrivate(struct sHandle *psHandle) +#else +IMG_HANDLE ParentIfPrivate(struct sHandle *psHandle) +#endif +{ +	return TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ? +			ParentHandle(psHandle) : IMG_NULL; +} + +/*! +****************************************************************************** + + @Function	InitKey + + @Description	Initialise a hash table key for the current process + + @Input		psBase - pointer to handle base structure +		aKey - pointer to key +		pvData - pointer to the resource the handle represents +		eType - type of resource + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(InitKey) +#endif +static INLINE +#if defined (SUPPORT_SID_INTERFACE) +IMG_VOID InitKey(HAND_KEY aKey, PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_SID hParent) +#else +IMG_VOID InitKey(HAND_KEY aKey, PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hParent) +#endif +{ +	PVR_UNREFERENCED_PARAMETER(psBase); + +	aKey[HAND_KEY_DATA] = (IMG_UINTPTR_T)pvData; +	aKey[HAND_KEY_TYPE] = (IMG_UINTPTR_T)eType; +	aKey[HAND_KEY_PARENT] = (IMG_UINTPTR_T)hParent; +} + +/*! +****************************************************************************** + + @Function	ReallocHandleArray + + @Description	Reallocate the handle array + + @Input		psBase - handle base. +		phBlockAlloc - pointer to block allocation handle. +		ui32NewCount - new handle count +		ui32OldCount - old handle count + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +static +PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCount) +{ +	struct sHandleIndex *psOldArray = psBase->psHandleArray; +	IMG_HANDLE hOldArrayBlockAlloc = psBase->hArrayBlockAlloc; +	IMG_UINT32 ui32OldCount = psBase->ui32TotalHandCount; +	struct sHandleIndex *psNewArray = IMG_NULL; +	IMG_HANDLE hNewArrayBlockAlloc = IMG_NULL; +	PVRSRV_ERROR eError; +	PVRSRV_ERROR eReturn = PVRSRV_OK; +	IMG_UINT32 ui32Index; + +	if (ui32NewCount == ui32OldCount) +	{ +		return PVRSRV_OK; +	} + +	if (ui32NewCount != 0 && !psBase->bPurgingEnabled && +		 ui32NewCount < ui32OldCount) +	{ +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	if (((ui32OldCount % HANDLE_BLOCK_SIZE) != 0) || +		((ui32NewCount % HANDLE_BLOCK_SIZE) != 0)) +	{ +		PVR_ASSERT((ui32OldCount % HANDLE_BLOCK_SIZE) == 0); +		PVR_ASSERT((ui32NewCount % HANDLE_BLOCK_SIZE) == 0); + +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	if (ui32NewCount != 0) +	{ +		/* Allocate new handle array */ +		eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, +			HANDLE_ARRAY_SIZE(ui32NewCount) * sizeof(struct sHandleIndex), +			(IMG_VOID **)&psNewArray, +			&hNewArrayBlockAlloc, +			"Memory Area"); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't allocate new handle array (%d)", eError)); +			eReturn = eError; +			goto error; +		} + +		if (ui32OldCount != 0) +		{ +			OSMemCopy(psNewArray, psOldArray, HANDLE_ARRAY_SIZE(MIN(ui32NewCount, ui32OldCount)) * sizeof(struct sHandleIndex)); +		} +	} + +	/* +	 * If the new handle array is smaller than the old one, free +	 * unused handle structures +	 */ +	for(ui32Index = ui32NewCount; ui32Index < ui32OldCount; ui32Index += HANDLE_BLOCK_SIZE) +	{ +		struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psOldArray, ui32Index); + +		eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, +				sizeof(struct sHandle) * HANDLE_BLOCK_SIZE, +				psIndex->psHandle, +				psIndex->hBlockAlloc); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free handle structures (%d)", eError)); +		} +	} + +	/* +	 * If the new handle array is bigger than the old one, allocate +	 * new handle structures +	 */ +	for(ui32Index = ui32OldCount; ui32Index < ui32NewCount; ui32Index += HANDLE_BLOCK_SIZE) +	{ +		/* PRQA S 0505 1 */ /* psNewArray is never NULL, see assert earlier */ +		struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psNewArray, ui32Index); + +		eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, +				sizeof(struct sHandle) * HANDLE_BLOCK_SIZE, +				(IMG_VOID **)&psIndex->psHandle, +				&psIndex->hBlockAlloc, +				"Memory Area"); +		if (eError != PVRSRV_OK) +		{ +			psIndex->psHandle = IMG_NULL; +			PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't allocate handle structures (%d)", eError)); +			eReturn = eError; +		} +		else +		{ +			IMG_UINT32 ui32SubIndex; + +			psIndex->ui32FreeHandBlockCount = HANDLE_BLOCK_SIZE; + +			for(ui32SubIndex = 0; ui32SubIndex < HANDLE_BLOCK_SIZE; ui32SubIndex++) +			{ +				struct sHandle *psHandle = psIndex->psHandle + ui32SubIndex; + + +				psHandle->ui32Index = ui32SubIndex + ui32Index; +				psHandle->eType = PVRSRV_HANDLE_TYPE_NONE; +				psHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE; +				psHandle->ui32NextIndexPlusOne  = 0; +			} +		} +	} +	if (eReturn != PVRSRV_OK) +	{ +		goto error; +	} + +#ifdef	DEBUG_MAX_HANDLE_COUNT +	/* Force handle failure to test error exit code */ +	if (ui32NewCount > DEBUG_MAX_HANDLE_COUNT) +	{ +		PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Max handle count (%u) reached", DEBUG_MAX_HANDLE_COUNT)); +		eReturn = PVRSRV_ERROR_OUT_OF_MEMORY; +		goto error; +	} +#endif + +	if (psOldArray != IMG_NULL) +	{ +		/* Free old handle array */ +		eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, +			HANDLE_ARRAY_SIZE(ui32OldCount) * sizeof(struct sHandleIndex), +			psOldArray, +			hOldArrayBlockAlloc); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free old handle array (%d)", eError)); +		} +	} + +	psBase->psHandleArray = psNewArray; +	psBase->hArrayBlockAlloc = hNewArrayBlockAlloc; +	psBase->ui32TotalHandCount = ui32NewCount; + +	if (ui32NewCount > ui32OldCount) +	{ +		/* Check for wraparound */ +		PVR_ASSERT(psBase->ui32FreeHandCount + (ui32NewCount - ui32OldCount) > psBase->ui32FreeHandCount); + +		/* PRQA S 3382 1 */ /* ui32NewCount always > ui32OldCount */ +		psBase->ui32FreeHandCount += (ui32NewCount - ui32OldCount); + +		/* +		 * If purging is enabled, there is no free handle list +		 * management, but as an optimization, when allocating +		 * new handles, we use ui32FirstFreeIndex to point to +		 * the first handle in a newly allocated block. +		 */ +		if (psBase->ui32FirstFreeIndex == 0) +		{ +			PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0); + +			psBase->ui32FirstFreeIndex = ui32OldCount; +		} +		else +		{ +			if (!psBase->bPurgingEnabled) +			{ +				PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0); +				PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0); + +				INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne = ui32OldCount + 1; +			} +		} + +		if (!psBase->bPurgingEnabled) +		{ +			psBase->ui32LastFreeIndexPlusOne = ui32NewCount; +		} +	} +	else +	{ +		PVR_ASSERT(ui32NewCount == 0 || psBase->bPurgingEnabled); +		PVR_ASSERT(ui32NewCount == 0 || psBase->ui32FirstFreeIndex <= ui32NewCount); +		PVR_ASSERT(psBase->ui32FreeHandCount - (ui32OldCount - ui32NewCount) < psBase->ui32FreeHandCount); + +		/* PRQA S 3382 1 */ /* ui32OldCount always >= ui32NewCount */ +		psBase->ui32FreeHandCount -= (ui32OldCount - ui32NewCount); + +		if (ui32NewCount == 0) +		{ +			psBase->ui32FirstFreeIndex = 0; +			psBase->ui32LastFreeIndexPlusOne = 0; +		} +	} + +	PVR_ASSERT(psBase->ui32FirstFreeIndex <= psBase->ui32TotalHandCount); + +	return PVRSRV_OK; + +error: +	PVR_ASSERT(eReturn != PVRSRV_OK); + +	if (psNewArray != IMG_NULL) +	{ +		/* Free any new handle structures that were allocated */ +		for(ui32Index = ui32OldCount; ui32Index < ui32NewCount; ui32Index += HANDLE_BLOCK_SIZE) +		{ +			struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psNewArray, ui32Index); +			if (psIndex->psHandle != IMG_NULL) +			{ +				eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, +						sizeof(struct sHandle) * HANDLE_BLOCK_SIZE, +						psIndex->psHandle, +						psIndex->hBlockAlloc); +				if (eError != PVRSRV_OK) +				{ +					PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free handle structures (%d)", eError)); +				} +			} +		} + +		/* Free new handle array */ +		eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, +			HANDLE_ARRAY_SIZE(ui32NewCount) * sizeof(struct sHandleIndex), +			psNewArray, +			hNewArrayBlockAlloc); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free new handle array (%d)", eError)); +		} +	} + +	return eReturn; +} + +/*! +****************************************************************************** + + @Function	FreeHandleArray + + @Description	Frees the handle array. +		The memory containing the array of handle structure +		pointers is deallocated. + + @Input		psBase - pointer to handle base structure + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +static PVRSRV_ERROR FreeHandleArray(PVRSRV_HANDLE_BASE *psBase) +{ +	return ReallocHandleArray(psBase, 0); +} + +/*! +****************************************************************************** + + @Function	FreeHandle + + @Description	Free a handle structure. + + @Input		psBase - pointer to handle base structure +		psHandle - pointer to handle structure + + @Return	PVRSRV_OK or PVRSRV_ERROR + +******************************************************************************/ +static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle) +{ +	HAND_KEY aKey; +	IMG_UINT32 ui32Index = HANDLE_PTR_TO_INDEX(psHandle); +	PVRSRV_ERROR eError; + +	/* +	 * If a handle allocated in batch mode is freed whilst still +	 * in batch mode, the type is set to PVRSRV_HANDLE_TYPE_NONE further +	 * down, to indicate the handle will not be used, but not actually +	 * freed.  The Free is completed when this function is called a +	 * second time as part of the batch commit or release. +	 */ + +	InitKey(aKey, psBase, psHandle->pvData, psHandle->eType, ParentIfPrivate(psHandle)); + +	if (!TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_MULTI) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) +	{ +#if defined (SUPPORT_SID_INTERFACE) +		IMG_SID hHandle; +		hHandle = (IMG_SID) HASH_Remove_Extended(psBase->psHashTab, aKey); +#else +		IMG_HANDLE hHandle; +		hHandle = (IMG_HANDLE) HASH_Remove_Extended(psBase->psHashTab, aKey); + +#endif + +		PVR_ASSERT(hHandle != IMG_NULL); +		PVR_ASSERT(hHandle == INDEX_TO_HANDLE(ui32Index)); +		PVR_UNREFERENCED_PARAMETER(hHandle); +	} + +	/* Unlink handle from parent */ +	UnlinkFromParent(psBase, psHandle); + +	/* Free children */ +	eError = IterateOverChildren(psBase, psHandle, FreeHandle); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "FreeHandle: Error whilst freeing subhandles (%d)", eError)); +		return eError; +	} + +	/* +	 * Clear the type here, so that a handle can no longer be looked +	 * up if it is only partially freed. +	 */ +	psHandle->eType = PVRSRV_HANDLE_TYPE_NONE; + +	if (BATCHED_HANDLE(psHandle) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) +	{ +		/* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */ +        SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle); +		/* +		 * If the handle was allocated in batch mode, delay the free +		 * until the batch commit or release. +		 */ +		return PVRSRV_OK; +	} + +	/* No free list management if purging is enabled */ +	if (!psBase->bPurgingEnabled) +	{ +		if (psBase->ui32FreeHandCount == 0) +		{ +			PVR_ASSERT(psBase->ui32FirstFreeIndex == 0); +			PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0); + +			psBase->ui32FirstFreeIndex =  ui32Index; +		} +		else +		{ +			/* +			 * Put the handle pointer on the end of the the free +			 * handle pointer linked list. +			 */ +			PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0); +			PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0); +			INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne =  ui32Index + 1; +		} + +		PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0); + +		/* Update the end of the free handle linked list */ +		psBase->ui32LastFreeIndexPlusOne = ui32Index + 1; +	} + +	psBase->ui32FreeHandCount++; +	INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)++; + +	PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)<= HANDLE_BLOCK_SIZE); + +#ifdef DEBUG +	{ +		IMG_UINT32 ui32BlockedIndex; +		IMG_UINT32 ui32FreeHandCount = 0; + +		for (ui32BlockedIndex = 0; ui32BlockedIndex < psBase->ui32TotalHandCount; ui32BlockedIndex += HANDLE_BLOCK_SIZE) +		{ +			ui32FreeHandCount += INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32BlockedIndex); +		} + +		PVR_ASSERT(ui32FreeHandCount == psBase->ui32FreeHandCount); +	} +#endif + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	FreeAllHandles + + @Description	Free all handles for a given handle base + + @Input		psBase - pointer to handle base structure + + @Return	PVRSRV_OK or PVRSRV_ERROR + +******************************************************************************/ +static PVRSRV_ERROR FreeAllHandles(PVRSRV_HANDLE_BASE *psBase) +{ +	IMG_UINT32 i; +	PVRSRV_ERROR eError = PVRSRV_OK; + +	if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount) +	{ +		return eError; +	} + +	for (i = 0; i < psBase->ui32TotalHandCount; i++) +	{ +		struct sHandle *psHandle; + +		psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, i); + +		if (psHandle->eType != PVRSRV_HANDLE_TYPE_NONE) +		{ +			eError = FreeHandle(psBase, psHandle); +			if (eError != PVRSRV_OK) +			{ +				PVR_DPF((PVR_DBG_ERROR, "FreeAllHandles: FreeHandle failed (%d)", eError)); +				break; +			} + +			/* Break out of loop if all the handles free */ +			if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount) +			{ +				break; +			} +		} +	} + +	return eError; +} + +/*! +****************************************************************************** + + @Function	FreeHandleBase + + @Description	Free a handle base. + + @Input		psHandleBase - pointer to handle base + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase) +{ +	PVRSRV_ERROR eError; + +	if (HANDLES_BATCHED(psBase)) +	{ +		PVR_DPF((PVR_DBG_WARNING, "FreeHandleBase: Uncommitted/Unreleased handle batch")); +		PVRSRVReleaseHandleBatch(psBase); +	} + +	/* Free the handle array */ +	eError = FreeAllHandles(psBase); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handles (%d)", eError)); +		return eError; +	} + +	/* Free the handle array */ +	eError = FreeHandleArray(psBase); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handle array (%d)", eError)); +		return eError; +	} + +	if (psBase->psHashTab != IMG_NULL) +	{ +		/* Free the hash table */ +		HASH_Delete(psBase->psHashTab); +	} + +	eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, +		sizeof(*psBase), +		psBase, +		psBase->hBaseBlockAlloc); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handle base (%d)", eError)); +		return eError; +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	FindHandle + + @Description	Find handle corresponding to a resource pointer + + @Input		psBase - pointer to handle base structure +		pvData - pointer to resource to be associated with the handle +		eType - the type of resource + + @Return	the handle, or IMG_NULL if not found + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(FindHandle) +#endif +static INLINE +#if defined (SUPPORT_SID_INTERFACE) +IMG_SID FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_SID hParent) +#else +IMG_HANDLE FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hParent) +#endif +{ +	HAND_KEY aKey; + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	InitKey(aKey, psBase, pvData, eType, hParent); + +#if defined (SUPPORT_SID_INTERFACE) +	return (IMG_SID) HASH_Retrieve_Extended(psBase->psHashTab, aKey); +#else +	return (IMG_HANDLE) HASH_Retrieve_Extended(psBase->psHashTab, aKey); +#endif +} + +/*! +****************************************************************************** + + @Function	IncreaseHandleArraySize + + @Description	Allocate some more free handles + + @Input		psBase - pointer to handle base structure +		ui32Delta - number of new handles required + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +static PVRSRV_ERROR IncreaseHandleArraySize(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Delta) +{ +	PVRSRV_ERROR eError; +	IMG_UINT32 ui32DeltaAdjusted = ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(ui32Delta); +	IMG_UINT32 ui32NewTotalHandCount = psBase->ui32TotalHandCount + ui32DeltaAdjusted; + +	PVR_ASSERT(ui32Delta != 0); + +	/* +	 * Check new count against max handle index, and check for wrap around. +	 */ +	if (ui32NewTotalHandCount > psBase->ui32MaxIndexPlusOne || ui32NewTotalHandCount <= psBase->ui32TotalHandCount) +	{ +		ui32NewTotalHandCount = psBase->ui32MaxIndexPlusOne; + +		ui32DeltaAdjusted = ui32NewTotalHandCount - psBase->ui32TotalHandCount; + +		if (ui32DeltaAdjusted < ui32Delta) +		{ +			PVR_DPF((PVR_DBG_ERROR, "IncreaseHandleArraySize: Maximum handle limit reached (%d)", psBase->ui32MaxIndexPlusOne)); +			return PVRSRV_ERROR_OUT_OF_MEMORY; +		} +	} + +	PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta); + +	/* Realloc handle pointer array */ +	eError = ReallocHandleArray(psBase, ui32NewTotalHandCount); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "IncreaseHandleArraySize: ReallocHandleArray failed (%d)", eError)); +		return eError; +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	EnsureFreeHandles + + @Description	Ensure there are enough free handles + + @Input		psBase - pointer to handle base structure +		ui32Free - number of free handles required + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +static PVRSRV_ERROR EnsureFreeHandles(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Free) +{ +	PVRSRV_ERROR eError; + +	if (ui32Free > psBase->ui32FreeHandCount) +	{ +		IMG_UINT32 ui32FreeHandDelta = ui32Free - psBase->ui32FreeHandCount; +		eError = IncreaseHandleArraySize(psBase, ui32FreeHandDelta); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR, "EnsureFreeHandles: Couldn't allocate %u handles to ensure %u free handles (IncreaseHandleArraySize failed with error %d)", ui32FreeHandDelta, ui32Free, eError)); + +			return eError; +		} +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	AllocHandle + + @Description	Allocate a new handle + + @Input		phHandle - location for new handle +		pvData - pointer to resource to be associated with the handle +		eType - the type of resource +		hParent - parent handle or IMG_NULL + + @Output	phHandle - points to new handle + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_SID hParent) +#else +static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_HANDLE hParent) +#endif +{ +	IMG_UINT32 ui32NewIndex = DEFAULT_MAX_INDEX_PLUS_ONE; +	struct sHandle *psNewHandle = IMG_NULL; +#if defined (SUPPORT_SID_INTERFACE) +	IMG_SID hHandle; +#else +	IMG_HANDLE hHandle; +#endif +	HAND_KEY aKey; +	PVRSRV_ERROR eError; + +	/* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */ +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); +	PVR_ASSERT(psBase != IMG_NULL); +	PVR_ASSERT(psBase->psHashTab != IMG_NULL); + +	if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) +	{ +		/* Handle must not already exist */ +		PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == IMG_NULL); +	} + +	if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase)) +	{ +		 PVR_DPF((PVR_DBG_WARNING, "AllocHandle: Handle batch size (%u) was too small, allocating additional space", psBase->ui32HandBatchSize));  +	} + +	/* Ensure there is a free handle */ +	eError = EnsureFreeHandles(psBase, 1); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "AllocHandle: EnsureFreeHandles failed (%d)", eError)); +		return eError; +	} +	PVR_ASSERT(psBase->ui32FreeHandCount != 0); + +	if (!psBase->bPurgingEnabled) +	{ +		/* Array index of first free handle */ +		ui32NewIndex = psBase->ui32FirstFreeIndex; + +		/* Get handle array entry */ +		psNewHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32NewIndex); +	} +	else +	{ +		IMG_UINT32 ui32BlockedIndex; + +		/* +		 * If purging is enabled, we always try to allocate handles +		 * at the front of the array, to increase the chances that +		 * the size of the handle array can be reduced by a purge. +		 * No linked list of free handles is kept; we search for +		 * free handles as required. +		 */ + +		/* +		 * ui32FirstFreeIndex should only be set when a new batch of +		 * handle structures is allocated, and should always be a +		 * multiple of the block size. +		 */ +		PVR_ASSERT((psBase->ui32FirstFreeIndex % HANDLE_BLOCK_SIZE) == 0); + +		for (ui32BlockedIndex = ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(psBase->ui32FirstFreeIndex); ui32BlockedIndex < psBase->ui32TotalHandCount; ui32BlockedIndex += HANDLE_BLOCK_SIZE) +		{ +			struct sHandleIndex *psIndex = BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, ui32BlockedIndex); + +			if (psIndex->ui32FreeHandBlockCount == 0) +			{ +				continue; +			} + +			for (ui32NewIndex = ui32BlockedIndex; ui32NewIndex < ui32BlockedIndex + HANDLE_BLOCK_SIZE; ui32NewIndex++) +			{ +				psNewHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32NewIndex); +				if (HANDLE_STRUCT_IS_FREE(psNewHandle)) +				{ +					break; +				} +			} +		} +		psBase->ui32FirstFreeIndex = 0; +		PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount); +	} +	PVR_ASSERT(psNewHandle != IMG_NULL); + +	/* Handle to be returned to client */ +	hHandle = INDEX_TO_HANDLE(ui32NewIndex); + +	/* +	 * If a data pointer can be associated with multiple handles, we +	 * don't put the handle in the hash table, as the data pointer +	 * may not map to a unique handle +	 */ +	if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) +	{ +		/* Initialise hash key */ +		InitKey(aKey, psBase, pvData, eType, hParent); + +		/* Put the new handle in the hash table */ +		if (!HASH_Insert_Extended(psBase->psHashTab, aKey, (IMG_UINTPTR_T)hHandle)) +		{ +			PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Couldn't add handle to hash table")); + +			return PVRSRV_ERROR_UNABLE_TO_ADD_HANDLE; +		} +	} + +	psBase->ui32FreeHandCount--; + +	PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) <= HANDLE_BLOCK_SIZE); +	PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) > 0); + +	INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex)--; + +	/* No free list management if purging is enabled */ +	if (!psBase->bPurgingEnabled) +	{ +		/* Check whether the last free handle has been allocated */ +		if (psBase->ui32FreeHandCount == 0) +		{ +			PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex); +			PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == (ui32NewIndex + 1)); + +			psBase->ui32LastFreeIndexPlusOne = 0; +			psBase->ui32FirstFreeIndex = 0; +		} +		else +		{ +			/* +			 * Update the first free handle index. +			 * If the "next free index plus one" field in the new +			 * handle structure is zero, the next free index is +			 * the index of the new handle plus one.  This +			 * convention has been adopted to simplify the +			 * initialisation of freshly allocated handle +			 * space. +			 */ +			psBase->ui32FirstFreeIndex = (psNewHandle->ui32NextIndexPlusOne == 0) ? +				ui32NewIndex + 1 : +				psNewHandle->ui32NextIndexPlusOne - 1; +		} +	} + +	/* Initialise the newly allocated handle */ +	PVR_ASSERT(psNewHandle->ui32Index == ui32NewIndex); + +	/* PRQA S 0505 1 */ /* psNewHandle is never NULL, see assert earlier */ +	psNewHandle->eType = eType; +	psNewHandle->pvData = pvData; +	psNewHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE; +	psNewHandle->eFlag = eFlag; + +	InitParentList(psNewHandle); +#if defined(DEBUG) +	PVR_ASSERT(NoChildren(psNewHandle)); +#endif + +	InitChildEntry(psNewHandle); +#if defined(DEBUG) +	PVR_ASSERT(NoParent(psNewHandle)); +#endif + +	if (HANDLES_BATCHED(psBase)) +	{ +		/* Add handle to batch list */ +		psNewHandle->ui32NextIndexPlusOne = psBase->ui32FirstBatchIndexPlusOne; + +		psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1; + +		/* PRQA S 1474 1 */ /* ignore warnings about enum types being modified */ +		SET_BATCHED_HANDLE(psNewHandle); +	} +	else +	{ +		psNewHandle->ui32NextIndexPlusOne = 0; +	} + +	/* Return the new handle to the client */ +	*phHandle = hHandle; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVAllocHandle + + @Description	Allocate a handle + + @Input		phHandle - location for new handle +		pvData - pointer to resource to be associated with the handle +		eType - the type of resource + + @Output	phHandle - points to new handle + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag) +#else +PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag) +#endif +{ +#if defined (SUPPORT_SID_INTERFACE) +	IMG_SID hHandle; +#else +	IMG_HANDLE hHandle; +#endif +	PVRSRV_ERROR eError; + +#if defined (SUPPORT_SID_INTERFACE) +	*phHandle = 0; +#else +	*phHandle = IMG_NULL; +#endif + +	if (HANDLES_BATCHED(psBase)) +	{ +		/* +		 * Increment the counter in case of failure.  It will be +		 * decremented on success. +		 */ +		psBase->ui32BatchHandAllocFailures++; +	} + +	/* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */ +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) +	{ +		/* See if there is already a handle for this data pointer */ +		hHandle = FindHandle(psBase, pvData, eType, IMG_NULL); +#if defined (SUPPORT_SID_INTERFACE) +		if (hHandle != 0) +#else +		if (hHandle != IMG_NULL) +#endif +		{ +			struct sHandle *psHandle; + +			eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); +			if (eError != PVRSRV_OK) +			{ +				PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandle: Lookup of existing handle failed")); +				return eError; +			} + +			/* +			 * If the client is willing to share a handle, and the +			 * existing handle is marked as shareable, return the +			 * existing handle. +			 */ +			if (TEST_FLAG(psHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED)) +			{ +				*phHandle = hHandle; +				eError = PVRSRV_OK; +				goto exit_ok; +			} +			 +#if defined (SUPPORT_SID_INTERFACE) +			PVR_DBG_BREAK +#endif +			return PVRSRV_ERROR_HANDLE_NOT_SHAREABLE; +		} +	} + +	eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, IMG_NULL); +	 +exit_ok: +	if (HANDLES_BATCHED(psBase) && (eError == PVRSRV_OK)) +	{ +		psBase->ui32BatchHandAllocFailures--; +	} + +	return eError; +} + +/*! +****************************************************************************** + + @Function	PVRSRVAllocSubHandle + + @Description	Allocate a subhandle + + @Input		phHandle - location for new subhandle +		pvData - pointer to resource to be associated with the subhandle +		eType - the type of resource +		hParent - parent handle + + @Output	phHandle - points to new subhandle + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_SID hParent) +#else +PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_HANDLE hParent) +#endif +{ +	struct sHandle *psPHand; +	struct sHandle *psCHand; +	PVRSRV_ERROR eError; +#if defined (SUPPORT_SID_INTERFACE) +	IMG_SID hParentKey; +	IMG_SID hHandle; + +	*phHandle = 0; +#else +	IMG_HANDLE hParentKey; +	IMG_HANDLE hHandle; + +	*phHandle = IMG_NULL; +#endif + +	if (HANDLES_BATCHED(psBase)) +	{ +		/* +		 * Increment the counter in case of failure.  It will be +		 * decremented on success. +		 */ +		psBase->ui32BatchHandAllocFailures++; +	} + +	/* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */ +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ? +			hParent : IMG_NULL; + +	/* Lookup the parent handle */ +	eError = GetHandleStructure(psBase, &psPHand, hParent, PVRSRV_HANDLE_TYPE_NONE); +	if (eError != PVRSRV_OK) +	{ +		return eError; +	} + +	if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) +	{ +		/* See if there is already a handle for this data pointer */ +		hHandle = FindHandle(psBase, pvData, eType, hParentKey); +#if defined (SUPPORT_SID_INTERFACE) +		if (hHandle != 0) +#else +		if (hHandle != IMG_NULL) +#endif +		{ +			struct sHandle *psCHandle; +			PVRSRV_ERROR eErr; + +			eErr = GetHandleStructure(psBase, &psCHandle, hHandle, eType); +			if (eErr != PVRSRV_OK) +			{ +				PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Lookup of existing handle failed")); +				return eErr; +			} + +			PVR_ASSERT(hParentKey != IMG_NULL && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent); + +			/* +			 * If the client is willing to share a handle, the +			 * existing handle is marked as shareable, and the +			 * existing handle has the same parent, return the +			 * existing handle. +			 */ +			if (TEST_FLAG(psCHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED) && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent) +			{ +				*phHandle = hHandle; +				goto exit_ok; +			} +#if defined (SUPPORT_SID_INTERFACE) +			PVR_DBG_BREAK +#endif +			return PVRSRV_ERROR_HANDLE_NOT_SHAREABLE; +		} +	} + +	eError = AllocHandle(psBase, &hHandle, pvData, eType, eFlag, hParentKey); +	if (eError != PVRSRV_OK) +	{ +		return eError; +	} + +	/* +	 * Get the parent handle structure again, in case the handle +	 * structure has moved (depending on the implementation +	 * of AllocHandle). +	 */ +	psPHand = HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hParent); + +	psCHand = HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle); + +	AdoptChild(psBase, psPHand, psCHand); + +	*phHandle = hHandle; + +exit_ok: +	if (HANDLES_BATCHED(psBase)) +	{ +		psBase->ui32BatchHandAllocFailures--; +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVFindHandle + + @Description	Find handle corresponding to a resource pointer + + @Input		phHandle - location for returned handle +		pvData - pointer to resource to be associated with the handle +		eType - the type of resource + + @Output	phHandle - points to handle + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType) +#else +PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType) +#endif +{ +#if defined (SUPPORT_SID_INTERFACE) +	IMG_SID hHandle; +#else +	IMG_HANDLE hHandle; +#endif + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	/* See if there is a handle for this data pointer */ +#if defined (SUPPORT_SID_INTERFACE) +	hHandle = (IMG_SID) FindHandle(psBase, pvData, eType, IMG_NULL); +#else +	hHandle = (IMG_HANDLE) FindHandle(psBase, pvData, eType, IMG_NULL); +#endif +	if (hHandle == IMG_NULL) +	{ +		return PVRSRV_ERROR_HANDLE_NOT_FOUND; +	} + +	*phHandle = hHandle; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVLookupHandleAnyType + + @Description	Lookup the data pointer and type corresponding to a handle + + @Input		ppvData - location to return data pointer +		peType - location to return handle type +		hHandle - handle from client + + @Output	ppvData - points to the data pointer +		peType - points to handle type + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_SID hHandle) +#else +PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_HANDLE hHandle) +#endif +{ +	struct sHandle *psHandle; +	PVRSRV_ERROR eError; + +	eError = GetHandleStructure(psBase, &psHandle, hHandle, PVRSRV_HANDLE_TYPE_NONE); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandleAnyType: Error looking up handle (%d)", eError)); +#if defined (SUPPORT_SID_INTERFACE) +		PVR_DBG_BREAK +#endif +		return eError; +	} + +	*ppvData = psHandle->pvData; +	*peType = psHandle->eType; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVLookupHandle + + @Description	Lookup the data pointer corresponding to a handle + + @Input		ppvData - location to return data pointer +		hHandle - handle from client +		eType - handle type + + @Output	ppvData - points to the data pointer + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) +#else +PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType) +#endif +{ +	struct sHandle *psHandle; +	PVRSRV_ERROR eError; + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); +#if defined (SUPPORT_SID_INTERFACE) +	PVR_ASSERT(hHandle != 0); +#endif + +	eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandle: Error looking up handle (%d)", eError)); +#if defined (SUPPORT_SID_INTERFACE) +		PVR_DBG_BREAK +#endif +		return eError; +	} + +	*ppvData = psHandle->pvData; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVLookupSubHandle + + @Description	Lookup the data pointer corresponding to a subhandle + + @Input		ppvData - location to return data pointer +		hHandle - handle from client +		eType - handle type +		hAncestor - ancestor handle + + @Output	ppvData - points to the data pointer + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType, IMG_SID hAncestor) +#else +PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hAncestor) +#endif +{ +	struct sHandle *psPHand; +	struct sHandle *psCHand; +	PVRSRV_ERROR eError; + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); +#if defined (SUPPORT_SID_INTERFACE) +	PVR_ASSERT(hHandle != 0); +#endif + +	eError = GetHandleStructure(psBase, &psCHand, hHandle, eType); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Error looking up subhandle (%d)", eError)); +		return eError; +	} + +	/* Look for hAncestor among the handle's ancestors */ +	for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor; ) +	{ +		eError = GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand), PVRSRV_HANDLE_TYPE_NONE); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Subhandle doesn't belong to given ancestor")); +			return PVRSRV_ERROR_INVALID_SUBHANDLE; +		} +	} + +	*ppvData = psCHand->pvData; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVGetParentHandle + + @Description	Lookup the parent of a handle + + @Input		phParent - location for returning parent handle +		hHandle - handle for which the parent handle is required +		eType - handle type +		hParent - parent handle + + @Output	*phParent - parent handle, or IMG_NULL if there is no parent + + @Return	Error code or PVRSRV_OK.  Note that not having a parent is +		not regarded as an error. + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phParent, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) +#else +PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *phParent, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType) +#endif +{ +	struct sHandle *psHandle; +	PVRSRV_ERROR eError; + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetParentHandle: Error looking up subhandle (%d)", eError)); +		return eError; +	} + +	*phParent = ParentHandle(psHandle); + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVLookupAndReleaseHandle + + @Description	Lookup the data pointer corresponding to a handle + + @Input		ppvData - location to return data pointer +		hHandle - handle from client +		eType - handle type +		eFlag - lookup flags + + @Output	ppvData - points to the data pointer + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) +#else +PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType) +#endif +{ +	struct sHandle *psHandle; +	PVRSRV_ERROR eError; + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupAndReleaseHandle: Error looking up handle (%d)", eError)); +#if defined (SUPPORT_SID_INTERFACE) +		PVR_DBG_BREAK +#endif +		return eError; +	} + +	*ppvData = psHandle->pvData; + +	eError = FreeHandle(psBase, psHandle); + +	return eError; +} + +/*! +****************************************************************************** + + @Function	PVRSRVReleaseHandle + + @Description	Release a handle that is no longer needed + + @Input 	hHandle - handle from client +		eType - handle type + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) +#else +PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType) +#endif +{ +	struct sHandle *psHandle; +	PVRSRV_ERROR eError; + +	PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + +	eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVReleaseHandle: Error looking up handle (%d)", eError)); +		return eError; +	} + +	eError = FreeHandle(psBase, psHandle); + +	return eError; +} + +/*! +****************************************************************************** + + @Function	PVRSRVNewHandleBatch + + @Description	Start a new handle batch + + @Input 	psBase		- handle base + @Input 	ui32BatchSize	- handle batch size + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32BatchSize) +{ +	PVRSRV_ERROR eError; + +	if (HANDLES_BATCHED(psBase)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: There is a handle batch already in use (size %u)", psBase->ui32HandBatchSize)); +		return  PVRSRV_ERROR_HANDLE_BATCH_IN_USE; +	} + +	if (ui32BatchSize == 0) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: Invalid batch size (%u)", ui32BatchSize)); +		return  PVRSRV_ERROR_INVALID_PARAMS; +	} + +	eError = EnsureFreeHandles(psBase, ui32BatchSize); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: EnsureFreeHandles failed (error %d)", eError)); +		return eError; +	} + +	psBase->ui32HandBatchSize = ui32BatchSize; + +	/* Record current number of handles */ +	psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount; + +	PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0); + +	PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0); + +	PVR_ASSERT(HANDLES_BATCHED(psBase)); + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVHandleBatchCommitOrRelease + + @Description	Release a handle batch + + @Input 	psBase	- handle base +		bCommit	- commit handles + + @Return	none + +******************************************************************************/ +static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit) +{ + +	IMG_UINT32 ui32IndexPlusOne; +	IMG_BOOL bCommitBatch = bCommit; + +	if (!HANDLES_BATCHED(psBase)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: There is no handle batch")); +		return PVRSRV_ERROR_INVALID_PARAMS; + +	} + +	if (psBase->ui32BatchHandAllocFailures != 0) +	{ +		if (bCommit) +		{ +			PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Attempting to commit batch with handle allocation failures.")); +		} +		bCommitBatch = IMG_FALSE; +	} +	/* +	 * The whole point of batched handles is to avoid handle allocation +	 * failures. +	 */ +	PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit); + +	ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne; +	while(ui32IndexPlusOne != 0) +	{ +		struct sHandle *psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32IndexPlusOne - 1); +		IMG_UINT32 ui32NextIndexPlusOne = psHandle->ui32NextIndexPlusOne; +		PVR_ASSERT(BATCHED_HANDLE(psHandle)); + +		psHandle->ui32NextIndexPlusOne = 0; + +		if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) +		{ +			PVRSRV_ERROR eError; + +			/* +			 * We need a complete free here.  If the handle +			 * is not partially free, set the handle as +			 * unbatched to avoid a partial free. +			 */ +			if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) +			{ +				/* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */ +				SET_UNBATCHED_HANDLE(psHandle); /* PRQA S 4130 */ /* mis-use of enums FIXME*/ +			} + +			eError = FreeHandle(psBase, psHandle); +			if (eError != PVRSRV_OK) +			{ +				 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Error freeing handle (%d)", eError)); +			} +			PVR_ASSERT(eError == PVRSRV_OK); +		} +		else +		{ +			/* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */ +			SET_UNBATCHED_HANDLE(psHandle); +		} + +		ui32IndexPlusOne = ui32NextIndexPlusOne; +	} + +#ifdef DEBUG +	if (psBase->ui32TotalHandCountPreBatch != psBase->ui32TotalHandCount) +	{ +		IMG_UINT32 ui32Delta = psBase->ui32TotalHandCount - psBase->ui32TotalHandCountPreBatch; + +		PVR_ASSERT(psBase->ui32TotalHandCount > psBase->ui32TotalHandCountPreBatch); + +		PVR_DPF((PVR_DBG_WARNING, "PVRSRVHandleBatchCommitOrRelease: The batch size was too small.  Batch size was %u, but needs to be %u", psBase->ui32HandBatchSize,  psBase->ui32HandBatchSize + ui32Delta)); + +	} +#endif + +	psBase->ui32HandBatchSize = 0; +	psBase->ui32FirstBatchIndexPlusOne = 0; +	psBase->ui32TotalHandCountPreBatch = 0; +	psBase->ui32BatchHandAllocFailures = 0; + +	if (psBase->ui32BatchHandAllocFailures != 0 && bCommit) +	{ +		PVR_ASSERT(!bCommitBatch); + +		return PVRSRV_ERROR_HANDLE_BATCH_COMMIT_FAILURE; +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVCommitHandleBatch + + @Description	Commit a handle batch + + @Input 	psBase	- handle base + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVCommitHandleBatch(PVRSRV_HANDLE_BASE *psBase) +{ +	return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE); +} + +/*! +****************************************************************************** + + @Function	PVRSRReleaseHandleBatch + + @Description	Release a handle batch + + @Input 	psBase	- handle base + + @Return	none + +******************************************************************************/ +IMG_VOID PVRSRVReleaseHandleBatch(PVRSRV_HANDLE_BASE *psBase) +{ +	(IMG_VOID) PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE); +} + +/*! +****************************************************************************** + + @Function	PVRSRVSetMaxHandle + + @Description	Set maximum handle number for given handle base + + @Input 	psBase - pointer to handle base structure +		ui32MaxHandle - Maximum handle number + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHandle) +{ +	IMG_UINT32 ui32MaxHandleRounded; + +	if (HANDLES_BATCHED(psBase)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set whilst in batch mode")); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	/* Validate the limit */ +	if (ui32MaxHandle  == 0 || ui32MaxHandle > DEFAULT_MAX_HANDLE) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit must be between %u and %u, inclusive", 0, DEFAULT_MAX_HANDLE)); + +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	/* The limit can only be set if no handles have been allocated */ +	if (psBase->ui32TotalHandCount != 0) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set because handles have already been allocated")); + +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	ui32MaxHandleRounded = ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(ui32MaxHandle); + +	/* +	 * Allow the maximum number of handles to be reduced, but never to +	 * zero. +	 */ +	if (ui32MaxHandleRounded != 0 && ui32MaxHandleRounded < psBase->ui32MaxIndexPlusOne) +	{ +		psBase->ui32MaxIndexPlusOne = ui32MaxHandleRounded; +	} + +	PVR_ASSERT(psBase->ui32MaxIndexPlusOne != 0); +	PVR_ASSERT(psBase->ui32MaxIndexPlusOne <= DEFAULT_MAX_INDEX_PLUS_ONE); +	PVR_ASSERT((psBase->ui32MaxIndexPlusOne % HANDLE_BLOCK_SIZE) == 0); + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVGetMaxHandle + + @Description	Get maximum handle number for given handle base + + @Input 	psBase - pointer to handle base structure + + @Output 	Maximum handle number, or 0 if handle limits not +		supported. + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +IMG_UINT32 PVRSRVGetMaxHandle(PVRSRV_HANDLE_BASE *psBase) +{ +	return psBase->ui32MaxIndexPlusOne; +} + +/*! +****************************************************************************** + + @Function	PVRSRVEnableHandlePurging + + @Description	Enable purging for a given handle base + + @Input 	psBase - pointer to handle base structure + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase) +{ +	if (psBase->bPurgingEnabled) +	{ +		PVR_DPF((PVR_DBG_WARNING, "PVRSRVEnableHandlePurging: Purging already enabled")); +		return PVRSRV_OK; +	} + +	/* Purging can only be enabled if no handles have been allocated */ +	if (psBase->ui32TotalHandCount != 0) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVEnableHandlePurging: Handles have already been allocated")); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	psBase->bPurgingEnabled = IMG_TRUE; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVPurgeHandles + + @Description	Purge handles for a given handle base + + @Input 	psBase - pointer to handle base structure + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase) +{ +	IMG_UINT32 ui32BlockIndex; +	IMG_UINT32 ui32NewHandCount; + +	if (!psBase->bPurgingEnabled) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Purging not enabled for this handle base")); +		return PVRSRV_ERROR_NOT_SUPPORTED; +	} + +	if (HANDLES_BATCHED(psBase)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Purging not allowed whilst in batch mode")); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	PVR_ASSERT((psBase->ui32TotalHandCount % HANDLE_BLOCK_SIZE) == 0); + +	for (ui32BlockIndex = INDEX_TO_BLOCK_INDEX(psBase->ui32TotalHandCount); ui32BlockIndex != 0; ui32BlockIndex--) +	{ +		if (psBase->psHandleArray[ui32BlockIndex - 1].ui32FreeHandBlockCount != HANDLE_BLOCK_SIZE) +		{ +			break; +		} +	} +	ui32NewHandCount = BLOCK_INDEX_TO_INDEX(ui32BlockIndex); + +	/* +	 * Check for a suitable decrease in the handle count. +	 */ +	if (ui32NewHandCount <= (psBase->ui32TotalHandCount/2)) +	{ +		PVRSRV_ERROR eError; + +		// PVR_TRACE((" PVRSRVPurgeHandles: reducing number of handles from %u to %u", psBase->ui32TotalHandCount, ui32NewHandCount)); + +		eError = ReallocHandleArray(psBase, ui32NewHandCount); +		if (eError != PVRSRV_OK) +		{ +			return eError; +		} +	} + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVAllocHandleBase + + @Description	Allocate a handle base structure for a process + + @Input 	ppsBase - pointer to handle base structure pointer + + @Output	ppsBase - points to handle base structure pointer + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase) +{ +	PVRSRV_HANDLE_BASE *psBase; +	IMG_HANDLE hBlockAlloc; +	PVRSRV_ERROR eError; + +	eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, +		sizeof(*psBase), +		(IMG_PVOID *)&psBase, +		&hBlockAlloc, +		"Handle Base"); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't allocate handle base (%d)", eError)); +		return eError; +	} +	OSMemSet(psBase, 0, sizeof(*psBase)); + +	/* Create hash table */ +	psBase->psHashTab = HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, sizeof(HAND_KEY), HASH_Func_Default, HASH_Key_Comp_Default); +	if (psBase->psHashTab == IMG_NULL) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't create data pointer hash table\n")); +		(IMG_VOID)PVRSRVFreeHandleBase(psBase); +		return PVRSRV_ERROR_UNABLE_TO_CREATE_HASH_TABLE; +	} + +	psBase->hBaseBlockAlloc = hBlockAlloc; + +	psBase->ui32MaxIndexPlusOne = DEFAULT_MAX_INDEX_PLUS_ONE; + +	*ppsBase = psBase; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function	PVRSRVFreeHandleBase + + @Description	Free a handle base structure + + @Input 	psBase - pointer to handle base structure + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVFreeHandleBase(PVRSRV_HANDLE_BASE *psBase) +{ +	PVRSRV_ERROR eError; + +	PVR_ASSERT(psBase != gpsKernelHandleBase); + +	eError = FreeHandleBase(psBase); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVFreeHandleBase: FreeHandleBase failed (%d)", eError)); +	} + +	return eError; +} + +/*! +****************************************************************************** + + @Function	PVRSRVHandleInit + + @Description	Initialise handle management + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVHandleInit(IMG_VOID) +{ +	PVRSRV_ERROR eError; + +	PVR_ASSERT(gpsKernelHandleBase == IMG_NULL); + +	eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleInit: PVRSRVAllocHandleBase failed (%d)", eError)); +		goto error; +	} + +	eError = PVRSRVEnableHandlePurging(gpsKernelHandleBase); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleInit: PVRSRVEnableHandlePurging failed (%d)", eError)); +		goto error; +	} + +	return PVRSRV_OK; +error: +	(IMG_VOID) PVRSRVHandleDeInit(); +	return eError; +} + +/*! +****************************************************************************** + + @Function	PVRSRVHandleDeInit + + @Description	De-initialise handle management + + @Return	Error code or PVRSRV_OK + +******************************************************************************/ +PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID) +{ +	PVRSRV_ERROR eError = PVRSRV_OK; + +	if (gpsKernelHandleBase != IMG_NULL) +	{ +		eError = FreeHandleBase(gpsKernelHandleBase); +		if (eError == PVRSRV_OK) +		{ +			gpsKernelHandleBase = IMG_NULL; +		} +		else +		{ +			PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleDeInit: FreeHandleBase failed (%d)", eError)); +		} +	} + +	return eError; +} +#else +/* disable warning about empty module */ +#endif	/* #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) */ +/****************************************************************************** + End of file (handle.c) +******************************************************************************/  |