[android-sdk/device-ti-proprietary-open.git] / jacinto6 / sgx_src / eurasia_km / services4 / srvkm / common / handle.c
1 /*************************************************************************/ /*!
2 @Title Resource Handle Manager
3 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
4 @Description Provide resource handle management
5 @License Dual MIT/GPLv2
7 The contents of this file are subject to the MIT license as set out below.
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 Alternatively, the contents of this file may be used under the terms of
20 the GNU General Public License Version 2 ("GPL") in which case the provisions
21 of GPL are applicable instead of those above.
23 If you wish to allow use of your version of this file only under the terms of
24 GPL, and not to allow others to use your version of this file under the terms
25 of the MIT license, indicate your decision by deleting the provisions above
26 and replace them with the notice and other provisions required by GPL as set
27 out in the file called "GPL-COPYING" included in this distribution. If you do
28 not delete the provisions above, a recipient may use your version of this file
29 under the terms of either the MIT license or GPL.
31 This License is also included in this distribution in the file called
32 "MIT-COPYING".
34 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
35 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
38 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */ /**************************************************************************/
43 #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)
44 /* See handle.h for a description of the handle API. */
46 /*
47 * There is no locking here. It is assumed the code is used in a single
48 * threaded environment. In particular, it is assumed that the code will
49 * never be called from an interrupt handler.
50 *
51 * The implmentation supports movable handle structures, allowing the address
52 * of a handle structure to change without having to fix up pointers in
53 * any of the handle structures. For example, the linked list mechanism
54 * used to link subhandles together uses handle array indices rather than
55 * pointers to the structures themselves.
56 */
58 #include <stddef.h>
60 #include "services_headers.h"
61 #include "handle.h"
63 #ifdef DEBUG
64 #define HANDLE_BLOCK_SHIFT 2
65 #else
66 #define HANDLE_BLOCK_SHIFT 8
67 #endif
69 #define DIVIDE_BY_BLOCK_SIZE(i) (((IMG_UINT32)(i)) >> HANDLE_BLOCK_SHIFT)
70 #define MULTIPLY_BY_BLOCK_SIZE(i) (((IMG_UINT32)(i)) << HANDLE_BLOCK_SHIFT)
72 #define HANDLE_BLOCK_SIZE MULTIPLY_BY_BLOCK_SIZE(1)
73 #define HANDLE_SUB_BLOCK_MASK (HANDLE_BLOCK_SIZE - 1)
74 #define HANDLE_BLOCK_MASK (~(HANDLE_SUB_BLOCK_MASK))
76 #define HANDLE_HASH_TAB_INIT_SIZE 32
78 #define INDEX_IS_VALID(psBase, i) ((i) < (psBase)->ui32TotalHandCount)
80 /* Valid handles are never NULL, but handle array indices are based from 0 */
81 #if defined (SUPPORT_SID_INTERFACE)
82 #define INDEX_TO_HANDLE(i) ((IMG_SID)((i) + 1))
83 #define HANDLE_TO_INDEX(h) ((IMG_UINT32)(h) - 1)
84 #else
85 #define INDEX_TO_HANDLE(i) ((IMG_HANDLE)((IMG_UINTPTR_T)(i) + 1))
86 #define HANDLE_TO_INDEX(h) ((IMG_UINT32)(IMG_UINTPTR_T)(h) - 1)
88 #endif
90 #define INDEX_TO_BLOCK_INDEX(i) DIVIDE_BY_BLOCK_SIZE(i)
91 #define BLOCK_INDEX_TO_INDEX(i) MULTIPLY_BY_BLOCK_SIZE(i)
92 #define INDEX_TO_SUB_BLOCK_INDEX(i) ((i) & HANDLE_SUB_BLOCK_MASK)
94 #define INDEX_TO_INDEX_STRUCT_PTR(psArray, i) (&((psArray)[INDEX_TO_BLOCK_INDEX(i)]))
95 #define BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, i) INDEX_TO_INDEX_STRUCT_PTR((psBase)->psHandleArray, i)
97 #define INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, i) (BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, i)->ui32FreeHandBlockCount)
99 #define INDEX_TO_HANDLE_STRUCT_PTR(psBase, i) (BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, i)->psHandle + INDEX_TO_SUB_BLOCK_INDEX(i))
101 #define HANDLE_TO_HANDLE_STRUCT_PTR(psBase, h) (INDEX_TO_HANDLE_STRUCT_PTR(psBase, HANDLE_TO_INDEX(h)))
103 #define HANDLE_PTR_TO_INDEX(psHandle) ((psHandle)->ui32Index)
104 #define HANDLE_PTR_TO_HANDLE(psHandle) INDEX_TO_HANDLE(HANDLE_PTR_TO_INDEX(psHandle))
106 #define ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(a) (HANDLE_BLOCK_MASK & (a))
107 #define ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(a) ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE((a) + HANDLE_BLOCK_SIZE - 1)
109 #define DEFAULT_MAX_HANDLE 0x7fffffffu
110 #define DEFAULT_MAX_INDEX_PLUS_ONE ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(DEFAULT_MAX_HANDLE)
112 #define HANDLES_BATCHED(psBase) ((psBase)->ui32HandBatchSize != 0)
114 #define HANDLE_ARRAY_SIZE(handleCount) DIVIDE_BY_BLOCK_SIZE(ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(handleCount))
116 #define SET_FLAG(v, f) ((IMG_VOID)((v) |= (f)))
117 #define CLEAR_FLAG(v, f) ((IMG_VOID)((v) &= ~(f)))
118 #define TEST_FLAG(v, f) ((IMG_BOOL)(((v) & (f)) != 0))
120 #define TEST_ALLOC_FLAG(psHandle, f) TEST_FLAG((psHandle)->eFlag, f)
122 #define SET_INTERNAL_FLAG(psHandle, f) SET_FLAG((psHandle)->eInternalFlag, f)
123 #define CLEAR_INTERNAL_FLAG(psHandle, f) CLEAR_FLAG((psHandle)->eInternalFlag, f)
124 #define TEST_INTERNAL_FLAG(psHandle, f) TEST_FLAG((psHandle)->eInternalFlag, f)
126 #define BATCHED_HANDLE(psHandle) TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
128 #define SET_BATCHED_HANDLE(psHandle) SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
130 #define SET_UNBATCHED_HANDLE(psHandle) CLEAR_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
132 #define BATCHED_HANDLE_PARTIALLY_FREE(psHandle) TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE)
134 #define SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle) SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE)
136 #define HANDLE_STRUCT_IS_FREE(psHandle) ((psHandle)->eType == PVRSRV_HANDLE_TYPE_NONE && (psHandle)->eInternalFlag == INTERNAL_HANDLE_FLAG_NONE)
138 #ifdef MIN
139 #undef MIN
140 #endif
142 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
144 /*
145 * Linked list structure. Used for both the list head and list items.
146 * Array indices, rather than pointers, are used to point to the next and
147 * previous items on the list.
148 */
149 struct sHandleList
150 {
151 IMG_UINT32 ui32Prev;
152 IMG_UINT32 ui32Next;
153 #if defined (SUPPORT_SID_INTERFACE)
154 IMG_SID hParent;
155 #else
156 IMG_HANDLE hParent;
157 #endif
158 };
160 enum ePVRSRVInternalHandleFlag
161 {
162 INTERNAL_HANDLE_FLAG_NONE = 0x00,
163 INTERNAL_HANDLE_FLAG_BATCHED = 0x01,
164 INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE = 0x02,
165 };
167 /* Handle structure */
168 struct sHandle
169 {
170 /* Handle type */
171 PVRSRV_HANDLE_TYPE eType;
173 /* Pointer to the data that the handle represents */
174 IMG_VOID *pvData;
176 /*
177 * When handles are on the free list, the value of the "next index
178 * plus one field" has the following meaning:
179 * zero - next handle is the one that follows this one,
180 * nonzero - the index of the next handle is the value minus one.
181 * This scheme means handle space can be initialised to all zeros.
182 *
183 * When this field is used to link together handles on a list
184 * other than the free list, zero indicates the end of the
185 * list, with nonzero the same as above.
186 */
187 IMG_UINT32 ui32NextIndexPlusOne;
189 /* Internal flags */
190 enum ePVRSRVInternalHandleFlag eInternalFlag;
192 /* Flags specified when the handle was allocated */
193 PVRSRV_HANDLE_ALLOC_FLAG eFlag;
195 /* Index of this handle in the handle array */
196 IMG_UINT32 ui32Index;
198 /* List head for subhandles of this handle */
199 struct sHandleList sChildren;
201 /* List entry for sibling subhandles */
202 struct sHandleList sSiblings;
203 };
205 /* Handle array index structure.
206 * The handle array is an array of index structures, reallocated as the number of
207 * handles increases.
208 * NOTE: There is one index structure per block of handles.
209 */
210 struct sHandleIndex
211 {
212 /* Pointer to first handle structure in the block */
213 struct sHandle *psHandle;
215 /* Block allocation cookie returned from OSAllocMem for the block of handles */
216 IMG_HANDLE hBlockAlloc;
218 /* Number of free handles in block */
219 IMG_UINT32 ui32FreeHandBlockCount;
220 };
222 struct _PVRSRV_HANDLE_BASE_
223 {
224 /* Handle returned from OSAllocMem for handle base allocation */
225 IMG_HANDLE hBaseBlockAlloc;
227 /* Handle returned from OSAllocMem for handle array allocation */
228 IMG_HANDLE hArrayBlockAlloc;
230 /* Pointer to array of pointers to handle structures */
231 struct sHandleIndex *psHandleArray;
233 /*
234 * Pointer to handle hash table.
235 * The hash table is used to do reverse lookups, converting data
236 * pointers to handles.
237 */
238 HASH_TABLE *psHashTab;
240 /* Number of free handles */
241 IMG_UINT32 ui32FreeHandCount;
243 /*
244 * If purging is not enabled, this is the array index of first free
245 * handle.
246 * If purging is enabled, this is the index to start searching for
247 * a free handle from. In this case it is usually zero, unless
248 * the handle array size has been increased due to lack of
249 * handles.
250 */
251 IMG_UINT32 ui32FirstFreeIndex;
253 /* Maximum handle index, plus one */
254 IMG_UINT32 ui32MaxIndexPlusOne;
256 /* Total number of handles, free and allocated */
257 IMG_UINT32 ui32TotalHandCount;
259 /*
260 * Index of the last free index, plus one. Not used if purging
261 * is enabled.
262 */
263 IMG_UINT32 ui32LastFreeIndexPlusOne;
265 /* Size of current handle batch, or zero if batching not enabled */
266 IMG_UINT32 ui32HandBatchSize;
268 /* Number of handles prior to start of current batch */
269 IMG_UINT32 ui32TotalHandCountPreBatch;
271 /* Index of first handle in batch, plus one */
272 IMG_UINT32 ui32FirstBatchIndexPlusOne;
274 /* Number of handle allocation failures in batch */
275 IMG_UINT32 ui32BatchHandAllocFailures;
277 /* Purging enabled.
278 * If purging is enabled, the size of the table can be reduced
279 * by removing free space at the end of the table. To make
280 * purging more likely to succeed, handles are allocated as
281 * far to the front of the table as possible. The first free
282 * handle is found by a linear search from the start of the table,
283 * and so no free handle list management is done.
284 */
285 IMG_BOOL bPurgingEnabled;
286 };
288 /*
289 * The key for the handle hash table is an array of three elements, the
290 * pointer to the resource, the resource type, and the process ID. The
291 * eHandKey enumeration gives the array indices of the elements making
292 * up the key.
293 */
294 enum eHandKey {
295 HAND_KEY_DATA = 0,
296 HAND_KEY_TYPE,
297 HAND_KEY_PARENT,
298 HAND_KEY_LEN /* Must be last item in list */
299 };
301 /*
302 * Kernel handle base structure. For handles that are not allocated on
303 * behalf of a particular process
304 */
305 PVRSRV_HANDLE_BASE *gpsKernelHandleBase = IMG_NULL;
307 /* HAND_KEY is the type of the hash table key */
308 typedef IMG_UINTPTR_T HAND_KEY[HAND_KEY_LEN];
310 /*!
311 ******************************************************************************
313 @Function HandleListInit
315 @Description Initialise a linked list structure embedded in a handle
316 structure.
318 @Input ui32Index - index of handle in the handle array
319 psList - pointer to linked list structure
320 hParent - parent handle, or IMG_NULL
322 ******************************************************************************/
323 #ifdef INLINE_IS_PRAGMA
324 #pragma inline(HandleListInit)
325 #endif
326 static INLINE
327 #if defined (SUPPORT_SID_INTERFACE)
328 IMG_VOID HandleListInit(IMG_UINT32 ui32Index, struct sHandleList *psList, IMG_SID hParent)
329 #else
330 IMG_VOID HandleListInit(IMG_UINT32 ui32Index, struct sHandleList *psList, IMG_HANDLE hParent)
331 #endif
332 {
333 psList->ui32Next = ui32Index;
334 psList->ui32Prev = ui32Index;
335 psList->hParent = hParent;
336 }
338 /*!
339 ******************************************************************************
341 @Function InitParentList
343 @Description Initialise the children list head in a handle structure.
344 The children are the subhandles of this handle.
346 @Input psHandle - pointer to handle structure
348 ******************************************************************************/
349 #ifdef INLINE_IS_PRAGMA
350 #pragma inline(InitParentList)
351 #endif
352 static INLINE
353 IMG_VOID InitParentList(struct sHandle *psHandle)
354 {
355 IMG_UINT32 ui32Parent = HANDLE_PTR_TO_INDEX(psHandle);
357 HandleListInit(ui32Parent, &psHandle->sChildren, INDEX_TO_HANDLE(ui32Parent));
358 }
360 /*!
361 ******************************************************************************
363 @Function InitChildEntry
365 @Description Initialise the child list entry in a handle structure.
366 The list entry is used to link together subhandles of
367 a given handle.
369 @Input psHandle - pointer to handle structure
371 ******************************************************************************/
372 #ifdef INLINE_IS_PRAGMA
373 #pragma inline(InitChildEntry)
374 #endif
375 static INLINE
376 IMG_VOID InitChildEntry(struct sHandle *psHandle)
377 {
378 HandleListInit(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings, IMG_NULL);
379 }
381 /*!
382 ******************************************************************************
384 @Function HandleListIsEmpty
386 @Description Determine whether a given linked list is empty.
388 @Input ui32Index - index of the handle containing the list head
389 psList - pointer to the list head
391 @Return IMG_TRUE if the list is empty, IMG_FALSE if it isn't.
393 ******************************************************************************/
394 #ifdef INLINE_IS_PRAGMA
395 #pragma inline(HandleListIsEmpty)
396 #endif
397 static INLINE
398 IMG_BOOL HandleListIsEmpty(IMG_UINT32 ui32Index, struct sHandleList *psList)
399 {
400 IMG_BOOL bIsEmpty;
402 bIsEmpty = (IMG_BOOL)(psList->ui32Next == ui32Index);
404 #ifdef DEBUG
405 {
406 IMG_BOOL bIsEmpty2;
408 bIsEmpty2 = (IMG_BOOL)(psList->ui32Prev == ui32Index);
409 PVR_ASSERT(bIsEmpty == bIsEmpty2);
410 }
411 #endif
413 return bIsEmpty;
414 }
416 #ifdef DEBUG
417 /*!
418 ******************************************************************************
420 @Function NoChildren
422 @Description Determine whether a handle has any subhandles
424 @Input psHandle - pointer to handle structure
426 @Return IMG_TRUE if the handle has no subhandles, IMG_FALSE if it does.
428 ******************************************************************************/
429 #ifdef INLINE_IS_PRAGMA
430 #pragma inline(NoChildren)
431 #endif
432 static INLINE
433 IMG_BOOL NoChildren(struct sHandle *psHandle)
434 {
435 PVR_ASSERT(psHandle->sChildren.hParent == HANDLE_PTR_TO_HANDLE(psHandle));
437 return HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sChildren);
438 }
440 /*!
441 ******************************************************************************
443 @Function NoParent
445 @Description Determine whether a handle is a subhandle
447 @Input psHandle - pointer to handle structure
449 @Return IMG_TRUE if the handle is not a subhandle, IMG_FALSE if it is.
451 ******************************************************************************/
452 #ifdef INLINE_IS_PRAGMA
453 #pragma inline(NoParent)
454 #endif
455 static INLINE
456 IMG_BOOL NoParent(struct sHandle *psHandle)
457 {
458 if (HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings))
459 {
460 PVR_ASSERT(psHandle->sSiblings.hParent == IMG_NULL);
462 return IMG_TRUE;
463 }
464 else
465 {
466 PVR_ASSERT(psHandle->sSiblings.hParent != IMG_NULL);
467 }
468 return IMG_FALSE;
469 }
470 #endif /*DEBUG*/
471 /*!
472 ******************************************************************************
474 @Function ParentHandle
476 @Description Determine the parent of a handle
478 @Input psHandle - pointer to handle structure
480 @Return Parent handle, or IMG_NULL if the handle is not a subhandle.
482 ******************************************************************************/
483 #ifdef INLINE_IS_PRAGMA
484 #pragma inline(ParentHandle)
485 #endif
486 static INLINE
487 #if defined (SUPPORT_SID_INTERFACE)
488 IMG_SID ParentHandle(struct sHandle *psHandle)
489 #else
490 IMG_HANDLE ParentHandle(struct sHandle *psHandle)
491 #endif
492 {
493 return psHandle->sSiblings.hParent;
494 }
496 /*
497 * The LIST_PTR_FROM_INDEX_AND_OFFSET macro is used to generate either a
498 * pointer to the subhandle list head, or a pointer to the linked list
499 * structure of an item on a subhandle list.
500 * The list head is itself on the list, but is at a different offset
501 * in the handle structure to the linked list structure for items on
502 * the list. The two linked list structures are differentiated by
503 * the third parameter, containing the parent index. The parent field
504 * in the list head structure references the handle structure that contains
505 * it. For items on the list, the parent field in the linked list structure
506 * references the parent handle, which will be different from the handle
507 * containing the linked list structure.
508 */
509 #define LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, i, p, po, eo) \
510 ((struct sHandleList *)((IMG_CHAR *)(INDEX_TO_HANDLE_STRUCT_PTR(psBase, i)) + (((i) == (p)) ? (po) : (eo))))
512 /*!
513 ******************************************************************************
515 @Function HandleListInsertBefore
517 @Description Insert a handle before a handle currently on the list.
519 @Input ui32InsIndex - index of handle to be inserted after
520 psIns - pointer to handle structure to be inserted after
521 uiParentOffset - offset to list head struct in handle structure
522 ui32EntryIndex - index of handle to be inserted
523 psEntry - pointer to handle structure of item to be inserted
524 uiEntryOffset - offset of list item struct in handle structure
526 ******************************************************************************/
527 #ifdef INLINE_IS_PRAGMA
528 #pragma inline(HandleListInsertBefore)
529 #endif
530 static INLINE
531 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)
532 {
533 /* PRQA S 3305 7 */ /*override stricter alignment warning */
534 struct sHandleList *psPrevIns = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psIns->ui32Prev, ui32ParentIndex, uiParentOffset, uiEntryOffset);
536 PVR_ASSERT(psEntry->hParent == IMG_NULL);
537 PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next);
538 PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset, uiParentOffset)->hParent == INDEX_TO_HANDLE(ui32ParentIndex));
540 psEntry->ui32Prev = psIns->ui32Prev;
541 psIns->ui32Prev = ui32EntryIndex;
542 psEntry->ui32Next = ui32InsIndex;
543 psPrevIns->ui32Next = ui32EntryIndex;
545 psEntry->hParent = INDEX_TO_HANDLE(ui32ParentIndex);
546 }
548 /*!
549 ******************************************************************************
551 @Function AdoptChild
553 @Description Assign a subhandle to a handle
555 @Input psParent - pointer to handle structure of parent handle
556 psChild - pointer to handle structure of child subhandle
558 ******************************************************************************/
559 #ifdef INLINE_IS_PRAGMA
560 #pragma inline(AdoptChild)
561 #endif
562 static INLINE
563 IMG_VOID AdoptChild(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, struct sHandle *psChild)
564 {
565 IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psParent->sChildren.hParent);
567 PVR_ASSERT(ui32Parent == HANDLE_PTR_TO_INDEX(psParent));
569 HandleListInsertBefore(psBase, ui32Parent, &psParent->sChildren, offsetof(struct sHandle, sChildren), HANDLE_PTR_TO_INDEX(psChild), &psChild->sSiblings, offsetof(struct sHandle, sSiblings), ui32Parent);
571 }
573 /*!
574 ******************************************************************************
576 @Function HandleListRemove
578 @Description Remove a handle from a list
580 @Input ui32EntryIndex - index of handle to be removed
581 psEntry - pointer to handle structure of item to be removed
582 uiEntryOffset - offset of list item struct in handle structure
583 uiParentOffset - offset to list head struct in handle structure
585 ******************************************************************************/
586 #ifdef INLINE_IS_PRAGMA
587 #pragma inline(HandleListRemove)
588 #endif
589 static INLINE
590 IMG_VOID HandleListRemove(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32EntryIndex, struct sHandleList *psEntry, IMG_SIZE_T uiEntryOffset, IMG_SIZE_T uiParentOffset)
591 {
592 if (!HandleListIsEmpty(ui32EntryIndex, psEntry))
593 {
594 /* PRQA S 3305 3 */ /*override stricter alignment warning */
595 struct sHandleList *psPrev = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Prev, HANDLE_TO_INDEX(psEntry->hParent), uiParentOffset, uiEntryOffset);
596 struct sHandleList *psNext = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Next, HANDLE_TO_INDEX(psEntry->hParent), uiParentOffset, uiEntryOffset);
598 /*
599 * The list head is on the list, and we don't want to
600 * remove it.
601 */
602 PVR_ASSERT(psEntry->hParent != IMG_NULL);
604 psPrev->ui32Next = psEntry->ui32Next;
605 psNext->ui32Prev = psEntry->ui32Prev;
607 HandleListInit(ui32EntryIndex, psEntry, IMG_NULL);
608 }
609 }
611 /*!
612 ******************************************************************************
614 @Function UnlinkFromParent
616 @Description Remove a subhandle from its parents list
618 @Input psHandle - pointer to handle structure of child subhandle
620 ******************************************************************************/
621 #ifdef INLINE_IS_PRAGMA
622 #pragma inline(UnlinkFromParent)
623 #endif
624 static INLINE
625 IMG_VOID UnlinkFromParent(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
626 {
627 HandleListRemove(psBase, HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings, offsetof(struct sHandle, sSiblings), offsetof(struct sHandle, sChildren));
628 }
630 /*!
631 ******************************************************************************
633 @Function HandleListIterate
635 @Description Iterate over the items in a list
637 @Input psHead - pointer to list head
638 uiParentOffset - offset to list head struct in handle structure
639 uiEntryOffset - offset of list item struct in handle structure
640 pfnIterFunc - function to be called for each handle in the list
642 ******************************************************************************/
643 #ifdef INLINE_IS_PRAGMA
644 #pragma inline(HandleListIterate)
645 #endif
646 static INLINE
647 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 *))
648 {
649 IMG_UINT32 ui32Index;
650 IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psHead->hParent);
652 PVR_ASSERT(psHead->hParent != IMG_NULL);
654 /*
655 * Follow the next chain from the list head until we reach
656 * the list head again, which signifies the end of the list.
657 */
658 for(ui32Index = psHead->ui32Next; ui32Index != ui32Parent; )
659 {
660 struct sHandle *psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32Index);
661 /* PRQA S 3305 2 */ /*override stricter alignment warning */
662 struct sHandleList *psEntry = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32Index, ui32Parent, uiParentOffset, uiEntryOffset);
663 PVRSRV_ERROR eError;
665 PVR_ASSERT(psEntry->hParent == psHead->hParent);
666 /*
667 * Get the next index now, in case the list item is
668 * modified by the iteration function.
669 */
670 ui32Index = psEntry->ui32Next;
672 eError = (*pfnIterFunc)(psBase, psHandle);
673 if (eError != PVRSRV_OK)
674 {
675 return eError;
676 }
677 }
679 return PVRSRV_OK;
680 }
682 /*!
683 ******************************************************************************
685 @Function IterateOverChildren
687 @Description Iterate over the subhandles of a parent handle
689 @Input psParent - pointer to parent handle structure
690 pfnIterFunc - function to be called for each subhandle
692 ******************************************************************************/
693 #ifdef INLINE_IS_PRAGMA
694 #pragma inline(IterateOverChildren)
695 #endif
696 static INLINE
697 PVRSRV_ERROR IterateOverChildren(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, struct sHandle *))
698 {
699 return HandleListIterate(psBase, &psParent->sChildren, offsetof(struct sHandle, sChildren), offsetof(struct sHandle, sSiblings), pfnIterFunc);
700 }
702 /*!
703 ******************************************************************************
705 @Function GetHandleStructure
707 @Description Get the handle structure for a given handle
709 @Input psBase - pointer to handle base structure
710 ppsHandle - location to return pointer to handle structure
711 hHandle - handle from client
712 eType - handle type or PVRSRV_HANDLE_TYPE_NONE if the
713 handle type is not to be checked.
715 @Output ppsHandle - points to a pointer to the handle structure
717 @Return Error code or PVRSRV_OK
719 ******************************************************************************/
720 #ifdef INLINE_IS_PRAGMA
721 #pragma inline(GetHandleStructure)
722 #endif
723 static INLINE
724 #if defined (SUPPORT_SID_INTERFACE)
725 PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **ppsHandle, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType)
726 #else
727 PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **ppsHandle, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
728 #endif
729 {
730 IMG_UINT32 ui32Index = HANDLE_TO_INDEX(hHandle);
731 struct sHandle *psHandle;
733 /* Check handle index is in range */
734 if (!INDEX_IS_VALID(psBase, ui32Index))
735 {
736 PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle index out of range (%u >= %u)", ui32Index, psBase->ui32TotalHandCount));
737 #if defined (SUPPORT_SID_INTERFACE)
738 PVR_DBG_BREAK
739 #endif
740 return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
741 }
743 psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32Index);
744 if (psHandle->eType == PVRSRV_HANDLE_TYPE_NONE)
745 {
746 PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle not allocated (index: %u)", ui32Index));
747 #if defined (SUPPORT_SID_INTERFACE)
748 PVR_DBG_BREAK
749 #endif
750 return PVRSRV_ERROR_HANDLE_NOT_ALLOCATED;
751 }
753 /*
754 * Unless PVRSRV_HANDLE_TYPE_NONE was passed in to this function,
755 * check handle is of the correct type.
756 */
757 if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandle->eType)
758 {
759 PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle type mismatch (%d != %d)", eType, psHandle->eType));
760 #if defined (SUPPORT_SID_INTERFACE)
761 PVR_DBG_BREAK
762 #endif
763 return PVRSRV_ERROR_HANDLE_TYPE_MISMATCH;
764 }
766 /* Return the handle structure */
767 *ppsHandle = psHandle;
769 return PVRSRV_OK;
770 }
772 /*!
773 ******************************************************************************
775 @Function ParentIfPrivate
777 @Description Return the parent handle if the handle was allocated
778 with PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE, else return
779 IMG_NULL
781 @Input psHandle - pointer to handle
783 @Return Parent handle, or IMG_NULL
785 ******************************************************************************/
786 #ifdef INLINE_IS_PRAGMA
787 #pragma inline(ParentIfPrivate)
788 #endif
789 static INLINE
790 #if defined (SUPPORT_SID_INTERFACE)
791 IMG_SID ParentIfPrivate(struct sHandle *psHandle)
792 #else
793 IMG_HANDLE ParentIfPrivate(struct sHandle *psHandle)
794 #endif
795 {
796 return TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
797 ParentHandle(psHandle) : IMG_NULL;
798 }
800 /*!
801 ******************************************************************************
803 @Function InitKey
805 @Description Initialise a hash table key for the current process
807 @Input psBase - pointer to handle base structure
808 aKey - pointer to key
809 pvData - pointer to the resource the handle represents
810 eType - type of resource
812 ******************************************************************************/
813 #ifdef INLINE_IS_PRAGMA
814 #pragma inline(InitKey)
815 #endif
816 static INLINE
817 #if defined (SUPPORT_SID_INTERFACE)
818 IMG_VOID InitKey(HAND_KEY aKey, PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_SID hParent)
819 #else
820 IMG_VOID InitKey(HAND_KEY aKey, PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hParent)
821 #endif
822 {
823 PVR_UNREFERENCED_PARAMETER(psBase);
825 aKey[HAND_KEY_DATA] = (IMG_UINTPTR_T)pvData;
826 aKey[HAND_KEY_TYPE] = (IMG_UINTPTR_T)eType;
827 aKey[HAND_KEY_PARENT] = (IMG_UINTPTR_T)hParent;
828 }
830 /*!
831 ******************************************************************************
833 @Function ReallocHandleArray
835 @Description Reallocate the handle array
837 @Input psBase - handle base.
838 phBlockAlloc - pointer to block allocation handle.
839 ui32NewCount - new handle count
840 ui32OldCount - old handle count
842 @Return Error code or PVRSRV_OK
844 ******************************************************************************/
845 static
846 PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCount)
847 {
848 struct sHandleIndex *psOldArray = psBase->psHandleArray;
849 IMG_HANDLE hOldArrayBlockAlloc = psBase->hArrayBlockAlloc;
850 IMG_UINT32 ui32OldCount = psBase->ui32TotalHandCount;
851 struct sHandleIndex *psNewArray = IMG_NULL;
852 IMG_HANDLE hNewArrayBlockAlloc = IMG_NULL;
853 PVRSRV_ERROR eError;
854 PVRSRV_ERROR eReturn = PVRSRV_OK;
855 IMG_UINT32 ui32Index;
857 if (ui32NewCount == ui32OldCount)
858 {
859 return PVRSRV_OK;
860 }
862 if (ui32NewCount != 0 && !psBase->bPurgingEnabled &&
863 ui32NewCount < ui32OldCount)
864 {
865 return PVRSRV_ERROR_INVALID_PARAMS;
866 }
868 if (((ui32OldCount % HANDLE_BLOCK_SIZE) != 0) ||
869 ((ui32NewCount % HANDLE_BLOCK_SIZE) != 0))
870 {
871 PVR_ASSERT((ui32OldCount % HANDLE_BLOCK_SIZE) == 0);
872 PVR_ASSERT((ui32NewCount % HANDLE_BLOCK_SIZE) == 0);
874 return PVRSRV_ERROR_INVALID_PARAMS;
875 }
877 if (ui32NewCount != 0)
878 {
879 /* Allocate new handle array */
880 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
881 HANDLE_ARRAY_SIZE(ui32NewCount) * sizeof(struct sHandleIndex),
882 (IMG_VOID **)&psNewArray,
883 &hNewArrayBlockAlloc,
884 "Memory Area");
885 if (eError != PVRSRV_OK)
886 {
887 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't allocate new handle array (%d)", eError));
888 eReturn = eError;
889 goto error;
890 }
892 if (ui32OldCount != 0)
893 {
894 OSMemCopy(psNewArray, psOldArray, HANDLE_ARRAY_SIZE(MIN(ui32NewCount, ui32OldCount)) * sizeof(struct sHandleIndex));
895 }
896 }
898 /*
899 * If the new handle array is smaller than the old one, free
900 * unused handle structures
901 */
902 for(ui32Index = ui32NewCount; ui32Index < ui32OldCount; ui32Index += HANDLE_BLOCK_SIZE)
903 {
904 struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psOldArray, ui32Index);
906 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
907 sizeof(struct sHandle) * HANDLE_BLOCK_SIZE,
908 psIndex->psHandle,
909 psIndex->hBlockAlloc);
910 if (eError != PVRSRV_OK)
911 {
912 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free handle structures (%d)", eError));
913 }
914 }
916 /*
917 * If the new handle array is bigger than the old one, allocate
918 * new handle structures
919 */
920 for(ui32Index = ui32OldCount; ui32Index < ui32NewCount; ui32Index += HANDLE_BLOCK_SIZE)
921 {
922 /* PRQA S 0505 1 */ /* psNewArray is never NULL, see assert earlier */
923 struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psNewArray, ui32Index);
925 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
926 sizeof(struct sHandle) * HANDLE_BLOCK_SIZE,
927 (IMG_VOID **)&psIndex->psHandle,
928 &psIndex->hBlockAlloc,
929 "Memory Area");
930 if (eError != PVRSRV_OK)
931 {
932 psIndex->psHandle = IMG_NULL;
933 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't allocate handle structures (%d)", eError));
934 eReturn = eError;
935 }
936 else
937 {
938 IMG_UINT32 ui32SubIndex;
940 psIndex->ui32FreeHandBlockCount = HANDLE_BLOCK_SIZE;
942 for(ui32SubIndex = 0; ui32SubIndex < HANDLE_BLOCK_SIZE; ui32SubIndex++)
943 {
944 struct sHandle *psHandle = psIndex->psHandle + ui32SubIndex;
947 psHandle->ui32Index = ui32SubIndex + ui32Index;
948 psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
949 psHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE;
950 psHandle->ui32NextIndexPlusOne = 0;
951 }
952 }
953 }
954 if (eReturn != PVRSRV_OK)
955 {
956 goto error;
957 }
959 #ifdef DEBUG_MAX_HANDLE_COUNT
960 /* Force handle failure to test error exit code */
961 if (ui32NewCount > DEBUG_MAX_HANDLE_COUNT)
962 {
963 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Max handle count (%u) reached", DEBUG_MAX_HANDLE_COUNT));
964 eReturn = PVRSRV_ERROR_OUT_OF_MEMORY;
965 goto error;
966 }
967 #endif
969 if (psOldArray != IMG_NULL)
970 {
971 /* Free old handle array */
972 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
973 HANDLE_ARRAY_SIZE(ui32OldCount) * sizeof(struct sHandleIndex),
974 psOldArray,
975 hOldArrayBlockAlloc);
976 if (eError != PVRSRV_OK)
977 {
978 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free old handle array (%d)", eError));
979 }
980 }
982 psBase->psHandleArray = psNewArray;
983 psBase->hArrayBlockAlloc = hNewArrayBlockAlloc;
984 psBase->ui32TotalHandCount = ui32NewCount;
986 if (ui32NewCount > ui32OldCount)
987 {
988 /* Check for wraparound */
989 PVR_ASSERT(psBase->ui32FreeHandCount + (ui32NewCount - ui32OldCount) > psBase->ui32FreeHandCount);
991 /* PRQA S 3382 1 */ /* ui32NewCount always > ui32OldCount */
992 psBase->ui32FreeHandCount += (ui32NewCount - ui32OldCount);
994 /*
995 * If purging is enabled, there is no free handle list
996 * management, but as an optimization, when allocating
997 * new handles, we use ui32FirstFreeIndex to point to
998 * the first handle in a newly allocated block.
999 */
1000 if (psBase->ui32FirstFreeIndex == 0)
1001 {
1002 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
1004 psBase->ui32FirstFreeIndex = ui32OldCount;
1005 }
1006 else
1007 {
1008 if (!psBase->bPurgingEnabled)
1009 {
1010 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0);
1011 PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0);
1013 INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne = ui32OldCount + 1;
1014 }
1015 }
1017 if (!psBase->bPurgingEnabled)
1018 {
1019 psBase->ui32LastFreeIndexPlusOne = ui32NewCount;
1020 }
1021 }
1022 else
1023 {
1024 PVR_ASSERT(ui32NewCount == 0 || psBase->bPurgingEnabled);
1025 PVR_ASSERT(ui32NewCount == 0 || psBase->ui32FirstFreeIndex <= ui32NewCount);
1026 PVR_ASSERT(psBase->ui32FreeHandCount - (ui32OldCount - ui32NewCount) < psBase->ui32FreeHandCount);
1028 /* PRQA S 3382 1 */ /* ui32OldCount always >= ui32NewCount */
1029 psBase->ui32FreeHandCount -= (ui32OldCount - ui32NewCount);
1031 if (ui32NewCount == 0)
1032 {
1033 psBase->ui32FirstFreeIndex = 0;
1034 psBase->ui32LastFreeIndexPlusOne = 0;
1035 }
1036 }
1038 PVR_ASSERT(psBase->ui32FirstFreeIndex <= psBase->ui32TotalHandCount);
1040 return PVRSRV_OK;
1042 error:
1043 PVR_ASSERT(eReturn != PVRSRV_OK);
1045 if (psNewArray != IMG_NULL)
1046 {
1047 /* Free any new handle structures that were allocated */
1048 for(ui32Index = ui32OldCount; ui32Index < ui32NewCount; ui32Index += HANDLE_BLOCK_SIZE)
1049 {
1050 struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psNewArray, ui32Index);
1051 if (psIndex->psHandle != IMG_NULL)
1052 {
1053 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1054 sizeof(struct sHandle) * HANDLE_BLOCK_SIZE,
1055 psIndex->psHandle,
1056 psIndex->hBlockAlloc);
1057 if (eError != PVRSRV_OK)
1058 {
1059 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free handle structures (%d)", eError));
1060 }
1061 }
1062 }
1064 /* Free new handle array */
1065 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1066 HANDLE_ARRAY_SIZE(ui32NewCount) * sizeof(struct sHandleIndex),
1067 psNewArray,
1068 hNewArrayBlockAlloc);
1069 if (eError != PVRSRV_OK)
1070 {
1071 PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Couldn't free new handle array (%d)", eError));
1072 }
1073 }
1075 return eReturn;
1076 }
1078 /*!
1079 ******************************************************************************
1081 @Function FreeHandleArray
1083 @Description Frees the handle array.
1084 The memory containing the array of handle structure
1085 pointers is deallocated.
1087 @Input psBase - pointer to handle base structure
1089 @Return Error code or PVRSRV_OK
1091 ******************************************************************************/
1092 static PVRSRV_ERROR FreeHandleArray(PVRSRV_HANDLE_BASE *psBase)
1093 {
1094 return ReallocHandleArray(psBase, 0);
1095 }
1097 /*!
1098 ******************************************************************************
1100 @Function FreeHandle
1102 @Description Free a handle structure.
1104 @Input psBase - pointer to handle base structure
1105 psHandle - pointer to handle structure
1107 @Return PVRSRV_OK or PVRSRV_ERROR
1109 ******************************************************************************/
1110 static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
1111 {
1112 HAND_KEY aKey;
1113 IMG_UINT32 ui32Index = HANDLE_PTR_TO_INDEX(psHandle);
1114 PVRSRV_ERROR eError;
1116 /*
1117 * If a handle allocated in batch mode is freed whilst still
1118 * in batch mode, the type is set to PVRSRV_HANDLE_TYPE_NONE further
1119 * down, to indicate the handle will not be used, but not actually
1120 * freed. The Free is completed when this function is called a
1121 * second time as part of the batch commit or release.
1122 */
1124 InitKey(aKey, psBase, psHandle->pvData, psHandle->eType, ParentIfPrivate(psHandle));
1126 if (!TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_MULTI) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
1127 {
1128 #if defined (SUPPORT_SID_INTERFACE)
1129 IMG_SID hHandle;
1130 hHandle = (IMG_SID) HASH_Remove_Extended(psBase->psHashTab, aKey);
1131 #else
1132 IMG_HANDLE hHandle;
1133 hHandle = (IMG_HANDLE) HASH_Remove_Extended(psBase->psHashTab, aKey);
1135 #endif
1137 PVR_ASSERT(hHandle != IMG_NULL);
1138 PVR_ASSERT(hHandle == INDEX_TO_HANDLE(ui32Index));
1139 PVR_UNREFERENCED_PARAMETER(hHandle);
1140 }
1142 /* Unlink handle from parent */
1143 UnlinkFromParent(psBase, psHandle);
1145 /* Free children */
1146 eError = IterateOverChildren(psBase, psHandle, FreeHandle);
1147 if (eError != PVRSRV_OK)
1148 {
1149 PVR_DPF((PVR_DBG_ERROR, "FreeHandle: Error whilst freeing subhandles (%d)", eError));
1150 return eError;
1151 }
1153 /*
1154 * Clear the type here, so that a handle can no longer be looked
1155 * up if it is only partially freed.
1156 */
1157 psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
1159 if (BATCHED_HANDLE(psHandle) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
1160 {
1161 /* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */
1162 SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle);
1163 /*
1164 * If the handle was allocated in batch mode, delay the free
1165 * until the batch commit or release.
1166 */
1167 return PVRSRV_OK;
1168 }
1170 /* No free list management if purging is enabled */
1171 if (!psBase->bPurgingEnabled)
1172 {
1173 if (psBase->ui32FreeHandCount == 0)
1174 {
1175 PVR_ASSERT(psBase->ui32FirstFreeIndex == 0);
1176 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
1178 psBase->ui32FirstFreeIndex = ui32Index;
1179 }
1180 else
1181 {
1182 /*
1183 * Put the handle pointer on the end of the the free
1184 * handle pointer linked list.
1185 */
1186 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0);
1187 PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0);
1188 INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne = ui32Index + 1;
1189 }
1191 PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0);
1193 /* Update the end of the free handle linked list */
1194 psBase->ui32LastFreeIndexPlusOne = ui32Index + 1;
1195 }
1197 psBase->ui32FreeHandCount++;
1198 INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)++;
1200 PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)<= HANDLE_BLOCK_SIZE);
1202 #ifdef DEBUG
1203 {
1204 IMG_UINT32 ui32BlockedIndex;
1205 IMG_UINT32 ui32FreeHandCount = 0;
1207 for (ui32BlockedIndex = 0; ui32BlockedIndex < psBase->ui32TotalHandCount; ui32BlockedIndex += HANDLE_BLOCK_SIZE)
1208 {
1209 ui32FreeHandCount += INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32BlockedIndex);
1210 }
1212 PVR_ASSERT(ui32FreeHandCount == psBase->ui32FreeHandCount);
1213 }
1214 #endif
1216 return PVRSRV_OK;
1217 }
1219 /*!
1220 ******************************************************************************
1222 @Function FreeAllHandles
1224 @Description Free all handles for a given handle base
1226 @Input psBase - pointer to handle base structure
1228 @Return PVRSRV_OK or PVRSRV_ERROR
1230 ******************************************************************************/
1231 static PVRSRV_ERROR FreeAllHandles(PVRSRV_HANDLE_BASE *psBase)
1232 {
1233 IMG_UINT32 i;
1234 PVRSRV_ERROR eError = PVRSRV_OK;
1236 if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount)
1237 {
1238 return eError;
1239 }
1241 for (i = 0; i < psBase->ui32TotalHandCount; i++)
1242 {
1243 struct sHandle *psHandle;
1245 psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, i);
1247 if (psHandle->eType != PVRSRV_HANDLE_TYPE_NONE)
1248 {
1249 eError = FreeHandle(psBase, psHandle);
1250 if (eError != PVRSRV_OK)
1251 {
1252 PVR_DPF((PVR_DBG_ERROR, "FreeAllHandles: FreeHandle failed (%d)", eError));
1253 break;
1254 }
1256 /* Break out of loop if all the handles free */
1257 if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount)
1258 {
1259 break;
1260 }
1261 }
1262 }
1264 return eError;
1265 }
1267 /*!
1268 ******************************************************************************
1270 @Function FreeHandleBase
1272 @Description Free a handle base.
1274 @Input psHandleBase - pointer to handle base
1276 @Return Error code or PVRSRV_OK
1278 ******************************************************************************/
1279 static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase)
1280 {
1281 PVRSRV_ERROR eError;
1283 if (HANDLES_BATCHED(psBase))
1284 {
1285 PVR_DPF((PVR_DBG_WARNING, "FreeHandleBase: Uncommitted/Unreleased handle batch"));
1286 PVRSRVReleaseHandleBatch(psBase);
1287 }
1289 /* Free the handle array */
1290 eError = FreeAllHandles(psBase);
1291 if (eError != PVRSRV_OK)
1292 {
1293 PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handles (%d)", eError));
1294 return eError;
1295 }
1297 /* Free the handle array */
1298 eError = FreeHandleArray(psBase);
1299 if (eError != PVRSRV_OK)
1300 {
1301 PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handle array (%d)", eError));
1302 return eError;
1303 }
1305 if (psBase->psHashTab != IMG_NULL)
1306 {
1307 /* Free the hash table */
1308 HASH_Delete(psBase->psHashTab);
1309 }
1311 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1312 sizeof(*psBase),
1313 psBase,
1314 psBase->hBaseBlockAlloc);
1315 if (eError != PVRSRV_OK)
1316 {
1317 PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handle base (%d)", eError));
1318 return eError;
1319 }
1321 return PVRSRV_OK;
1322 }
1324 /*!
1325 ******************************************************************************
1327 @Function FindHandle
1329 @Description Find handle corresponding to a resource pointer
1331 @Input psBase - pointer to handle base structure
1332 pvData - pointer to resource to be associated with the handle
1333 eType - the type of resource
1335 @Return the handle, or IMG_NULL if not found
1337 ******************************************************************************/
1338 #ifdef INLINE_IS_PRAGMA
1339 #pragma inline(FindHandle)
1340 #endif
1341 static INLINE
1342 #if defined (SUPPORT_SID_INTERFACE)
1343 IMG_SID FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_SID hParent)
1344 #else
1345 IMG_HANDLE FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hParent)
1346 #endif
1347 {
1348 HAND_KEY aKey;
1350 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1352 InitKey(aKey, psBase, pvData, eType, hParent);
1354 #if defined (SUPPORT_SID_INTERFACE)
1355 return (IMG_SID) HASH_Retrieve_Extended(psBase->psHashTab, aKey);
1356 #else
1357 return (IMG_HANDLE) HASH_Retrieve_Extended(psBase->psHashTab, aKey);
1358 #endif
1359 }
1361 /*!
1362 ******************************************************************************
1364 @Function IncreaseHandleArraySize
1366 @Description Allocate some more free handles
1368 @Input psBase - pointer to handle base structure
1369 ui32Delta - number of new handles required
1371 @Return Error code or PVRSRV_OK
1373 ******************************************************************************/
1374 static PVRSRV_ERROR IncreaseHandleArraySize(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Delta)
1375 {
1376 PVRSRV_ERROR eError;
1377 IMG_UINT32 ui32DeltaAdjusted = ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(ui32Delta);
1378 IMG_UINT32 ui32NewTotalHandCount = psBase->ui32TotalHandCount + ui32DeltaAdjusted;
1380 PVR_ASSERT(ui32Delta != 0);
1382 /*
1383 * Check new count against max handle index, and check for wrap around.
1384 */
1385 if (ui32NewTotalHandCount > psBase->ui32MaxIndexPlusOne || ui32NewTotalHandCount <= psBase->ui32TotalHandCount)
1386 {
1387 ui32NewTotalHandCount = psBase->ui32MaxIndexPlusOne;
1389 ui32DeltaAdjusted = ui32NewTotalHandCount - psBase->ui32TotalHandCount;
1391 if (ui32DeltaAdjusted < ui32Delta)
1392 {
1393 PVR_DPF((PVR_DBG_ERROR, "IncreaseHandleArraySize: Maximum handle limit reached (%d)", psBase->ui32MaxIndexPlusOne));
1394 return PVRSRV_ERROR_OUT_OF_MEMORY;
1395 }
1396 }
1398 PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta);
1400 /* Realloc handle pointer array */
1401 eError = ReallocHandleArray(psBase, ui32NewTotalHandCount);
1402 if (eError != PVRSRV_OK)
1403 {
1404 PVR_DPF((PVR_DBG_ERROR, "IncreaseHandleArraySize: ReallocHandleArray failed (%d)", eError));
1405 return eError;
1406 }
1408 return PVRSRV_OK;
1409 }
1411 /*!
1412 ******************************************************************************
1414 @Function EnsureFreeHandles
1416 @Description Ensure there are enough free handles
1418 @Input psBase - pointer to handle base structure
1419 ui32Free - number of free handles required
1421 @Return Error code or PVRSRV_OK
1423 ******************************************************************************/
1424 static PVRSRV_ERROR EnsureFreeHandles(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Free)
1425 {
1426 PVRSRV_ERROR eError;
1428 if (ui32Free > psBase->ui32FreeHandCount)
1429 {
1430 IMG_UINT32 ui32FreeHandDelta = ui32Free - psBase->ui32FreeHandCount;
1431 eError = IncreaseHandleArraySize(psBase, ui32FreeHandDelta);
1432 if (eError != PVRSRV_OK)
1433 {
1434 PVR_DPF((PVR_DBG_ERROR, "EnsureFreeHandles: Couldn't allocate %u handles to ensure %u free handles (IncreaseHandleArraySize failed with error %d)", ui32FreeHandDelta, ui32Free, eError));
1436 return eError;
1437 }
1438 }
1440 return PVRSRV_OK;
1441 }
1443 /*!
1444 ******************************************************************************
1446 @Function AllocHandle
1448 @Description Allocate a new handle
1450 @Input phHandle - location for new handle
1451 pvData - pointer to resource to be associated with the handle
1452 eType - the type of resource
1453 hParent - parent handle or IMG_NULL
1455 @Output phHandle - points to new handle
1457 @Return Error code or PVRSRV_OK
1459 ******************************************************************************/
1460 #if defined (SUPPORT_SID_INTERFACE)
1461 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)
1462 #else
1463 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)
1464 #endif
1465 {
1466 IMG_UINT32 ui32NewIndex = DEFAULT_MAX_INDEX_PLUS_ONE;
1467 struct sHandle *psNewHandle = IMG_NULL;
1468 #if defined (SUPPORT_SID_INTERFACE)
1469 IMG_SID hHandle;
1470 #else
1471 IMG_HANDLE hHandle;
1472 #endif
1473 HAND_KEY aKey;
1474 PVRSRV_ERROR eError;
1476 /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1477 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1478 PVR_ASSERT(psBase != IMG_NULL);
1479 PVR_ASSERT(psBase->psHashTab != IMG_NULL);
1481 if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1482 {
1483 /* Handle must not already exist */
1484 PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == IMG_NULL);
1485 }
1487 if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase))
1488 {
1489 PVR_DPF((PVR_DBG_WARNING, "AllocHandle: Handle batch size (%u) was too small, allocating additional space", psBase->ui32HandBatchSize));
1490 }
1492 /* Ensure there is a free handle */
1493 eError = EnsureFreeHandles(psBase, 1);
1494 if (eError != PVRSRV_OK)
1495 {
1496 PVR_DPF((PVR_DBG_ERROR, "AllocHandle: EnsureFreeHandles failed (%d)", eError));
1497 return eError;
1498 }
1499 PVR_ASSERT(psBase->ui32FreeHandCount != 0);
1501 if (!psBase->bPurgingEnabled)
1502 {
1503 /* Array index of first free handle */
1504 ui32NewIndex = psBase->ui32FirstFreeIndex;
1506 /* Get handle array entry */
1507 psNewHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32NewIndex);
1508 }
1509 else
1510 {
1511 IMG_UINT32 ui32BlockedIndex;
1513 /*
1514 * If purging is enabled, we always try to allocate handles
1515 * at the front of the array, to increase the chances that
1516 * the size of the handle array can be reduced by a purge.
1517 * No linked list of free handles is kept; we search for
1518 * free handles as required.
1519 */
1521 /*
1522 * ui32FirstFreeIndex should only be set when a new batch of
1523 * handle structures is allocated, and should always be a
1524 * multiple of the block size.
1525 */
1526 PVR_ASSERT((psBase->ui32FirstFreeIndex % HANDLE_BLOCK_SIZE) == 0);
1528 for (ui32BlockedIndex = ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(psBase->ui32FirstFreeIndex); ui32BlockedIndex < psBase->ui32TotalHandCount; ui32BlockedIndex += HANDLE_BLOCK_SIZE)
1529 {
1530 struct sHandleIndex *psIndex = BASE_AND_INDEX_TO_INDEX_STRUCT_PTR(psBase, ui32BlockedIndex);
1532 if (psIndex->ui32FreeHandBlockCount == 0)
1533 {
1534 continue;
1535 }
1537 for (ui32NewIndex = ui32BlockedIndex; ui32NewIndex < ui32BlockedIndex + HANDLE_BLOCK_SIZE; ui32NewIndex++)
1538 {
1539 psNewHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32NewIndex);
1540 if (HANDLE_STRUCT_IS_FREE(psNewHandle))
1541 {
1542 break;
1543 }
1544 }
1545 }
1546 psBase->ui32FirstFreeIndex = 0;
1547 PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount);
1548 }
1549 PVR_ASSERT(psNewHandle != IMG_NULL);
1551 /* Handle to be returned to client */
1552 hHandle = INDEX_TO_HANDLE(ui32NewIndex);
1554 /*
1555 * If a data pointer can be associated with multiple handles, we
1556 * don't put the handle in the hash table, as the data pointer
1557 * may not map to a unique handle
1558 */
1559 if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1560 {
1561 /* Initialise hash key */
1562 InitKey(aKey, psBase, pvData, eType, hParent);
1564 /* Put the new handle in the hash table */
1565 if (!HASH_Insert_Extended(psBase->psHashTab, aKey, (IMG_UINTPTR_T)hHandle))
1566 {
1567 PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Couldn't add handle to hash table"));
1569 return PVRSRV_ERROR_UNABLE_TO_ADD_HANDLE;
1570 }
1571 }
1573 psBase->ui32FreeHandCount--;
1575 PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) <= HANDLE_BLOCK_SIZE);
1576 PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) > 0);
1578 INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex)--;
1580 /* No free list management if purging is enabled */
1581 if (!psBase->bPurgingEnabled)
1582 {
1583 /* Check whether the last free handle has been allocated */
1584 if (psBase->ui32FreeHandCount == 0)
1585 {
1586 PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex);
1587 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == (ui32NewIndex + 1));
1589 psBase->ui32LastFreeIndexPlusOne = 0;
1590 psBase->ui32FirstFreeIndex = 0;
1591 }
1592 else
1593 {
1594 /*
1595 * Update the first free handle index.
1596 * If the "next free index plus one" field in the new
1597 * handle structure is zero, the next free index is
1598 * the index of the new handle plus one. This
1599 * convention has been adopted to simplify the
1600 * initialisation of freshly allocated handle
1601 * space.
1602 */
1603 psBase->ui32FirstFreeIndex = (psNewHandle->ui32NextIndexPlusOne == 0) ?
1604 ui32NewIndex + 1 :
1605 psNewHandle->ui32NextIndexPlusOne - 1;
1606 }
1607 }
1609 /* Initialise the newly allocated handle */
1610 PVR_ASSERT(psNewHandle->ui32Index == ui32NewIndex);
1612 /* PRQA S 0505 1 */ /* psNewHandle is never NULL, see assert earlier */
1613 psNewHandle->eType = eType;
1614 psNewHandle->pvData = pvData;
1615 psNewHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE;
1616 psNewHandle->eFlag = eFlag;
1618 InitParentList(psNewHandle);
1619 #if defined(DEBUG)
1620 PVR_ASSERT(NoChildren(psNewHandle));
1621 #endif
1623 InitChildEntry(psNewHandle);
1624 #if defined(DEBUG)
1625 PVR_ASSERT(NoParent(psNewHandle));
1626 #endif
1628 if (HANDLES_BATCHED(psBase))
1629 {
1630 /* Add handle to batch list */
1631 psNewHandle->ui32NextIndexPlusOne = psBase->ui32FirstBatchIndexPlusOne;
1633 psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1;
1635 /* PRQA S 1474 1 */ /* ignore warnings about enum types being modified */
1636 SET_BATCHED_HANDLE(psNewHandle);
1637 }
1638 else
1639 {
1640 psNewHandle->ui32NextIndexPlusOne = 0;
1641 }
1643 /* Return the new handle to the client */
1644 *phHandle = hHandle;
1646 return PVRSRV_OK;
1647 }
1649 /*!
1650 ******************************************************************************
1652 @Function PVRSRVAllocHandle
1654 @Description Allocate a handle
1656 @Input phHandle - location for new handle
1657 pvData - pointer to resource to be associated with the handle
1658 eType - the type of resource
1660 @Output phHandle - points to new handle
1662 @Return Error code or PVRSRV_OK
1664 ******************************************************************************/
1665 #if defined (SUPPORT_SID_INTERFACE)
1666 PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag)
1667 #else
1668 PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag)
1669 #endif
1670 {
1671 #if defined (SUPPORT_SID_INTERFACE)
1672 IMG_SID hHandle;
1673 #else
1674 IMG_HANDLE hHandle;
1675 #endif
1676 PVRSRV_ERROR eError;
1678 #if defined (SUPPORT_SID_INTERFACE)
1679 *phHandle = 0;
1680 #else
1681 *phHandle = IMG_NULL;
1682 #endif
1684 if (HANDLES_BATCHED(psBase))
1685 {
1686 /*
1687 * Increment the counter in case of failure. It will be
1688 * decremented on success.
1689 */
1690 psBase->ui32BatchHandAllocFailures++;
1691 }
1693 /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1694 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1696 if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1697 {
1698 /* See if there is already a handle for this data pointer */
1699 hHandle = FindHandle(psBase, pvData, eType, IMG_NULL);
1700 #if defined (SUPPORT_SID_INTERFACE)
1701 if (hHandle != 0)
1702 #else
1703 if (hHandle != IMG_NULL)
1704 #endif
1705 {
1706 struct sHandle *psHandle;
1708 eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1709 if (eError != PVRSRV_OK)
1710 {
1711 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandle: Lookup of existing handle failed"));
1712 return eError;
1713 }
1715 /*
1716 * If the client is willing to share a handle, and the
1717 * existing handle is marked as shareable, return the
1718 * existing handle.
1719 */
1720 if (TEST_FLAG(psHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED))
1721 {
1722 *phHandle = hHandle;
1723 eError = PVRSRV_OK;
1724 goto exit_ok;
1725 }
1727 #if defined (SUPPORT_SID_INTERFACE)
1728 PVR_DBG_BREAK
1729 #endif
1730 return PVRSRV_ERROR_HANDLE_NOT_SHAREABLE;
1731 }
1732 }
1734 eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, IMG_NULL);
1736 exit_ok:
1737 if (HANDLES_BATCHED(psBase) && (eError == PVRSRV_OK))
1738 {
1739 psBase->ui32BatchHandAllocFailures--;
1740 }
1742 return eError;
1743 }
1745 /*!
1746 ******************************************************************************
1748 @Function PVRSRVAllocSubHandle
1750 @Description Allocate a subhandle
1752 @Input phHandle - location for new subhandle
1753 pvData - pointer to resource to be associated with the subhandle
1754 eType - the type of resource
1755 hParent - parent handle
1757 @Output phHandle - points to new subhandle
1759 @Return Error code or PVRSRV_OK
1761 ******************************************************************************/
1762 #if defined (SUPPORT_SID_INTERFACE)
1763 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)
1764 #else
1765 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)
1766 #endif
1767 {
1768 struct sHandle *psPHand;
1769 struct sHandle *psCHand;
1770 PVRSRV_ERROR eError;
1771 #if defined (SUPPORT_SID_INTERFACE)
1772 IMG_SID hParentKey;
1773 IMG_SID hHandle;
1775 *phHandle = 0;
1776 #else
1777 IMG_HANDLE hParentKey;
1778 IMG_HANDLE hHandle;
1780 *phHandle = IMG_NULL;
1781 #endif
1783 if (HANDLES_BATCHED(psBase))
1784 {
1785 /*
1786 * Increment the counter in case of failure. It will be
1787 * decremented on success.
1788 */
1789 psBase->ui32BatchHandAllocFailures++;
1790 }
1792 /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1793 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1795 hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
1796 hParent : IMG_NULL;
1798 /* Lookup the parent handle */
1799 eError = GetHandleStructure(psBase, &psPHand, hParent, PVRSRV_HANDLE_TYPE_NONE);
1800 if (eError != PVRSRV_OK)
1801 {
1802 return eError;
1803 }
1805 if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1806 {
1807 /* See if there is already a handle for this data pointer */
1808 hHandle = FindHandle(psBase, pvData, eType, hParentKey);
1809 #if defined (SUPPORT_SID_INTERFACE)
1810 if (hHandle != 0)
1811 #else
1812 if (hHandle != IMG_NULL)
1813 #endif
1814 {
1815 struct sHandle *psCHandle;
1816 PVRSRV_ERROR eErr;
1818 eErr = GetHandleStructure(psBase, &psCHandle, hHandle, eType);
1819 if (eErr != PVRSRV_OK)
1820 {
1821 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Lookup of existing handle failed"));
1822 return eErr;
1823 }
1825 PVR_ASSERT(hParentKey != IMG_NULL && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent);
1827 /*
1828 * If the client is willing to share a handle, the
1829 * existing handle is marked as shareable, and the
1830 * existing handle has the same parent, return the
1831 * existing handle.
1832 */
1833 if (TEST_FLAG(psCHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED) && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent)
1834 {
1835 *phHandle = hHandle;
1836 goto exit_ok;
1837 }
1838 #if defined (SUPPORT_SID_INTERFACE)
1839 PVR_DBG_BREAK
1840 #endif
1841 return PVRSRV_ERROR_HANDLE_NOT_SHAREABLE;
1842 }
1843 }
1845 eError = AllocHandle(psBase, &hHandle, pvData, eType, eFlag, hParentKey);
1846 if (eError != PVRSRV_OK)
1847 {
1848 return eError;
1849 }
1851 /*
1852 * Get the parent handle structure again, in case the handle
1853 * structure has moved (depending on the implementation
1854 * of AllocHandle).
1855 */
1856 psPHand = HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hParent);
1858 psCHand = HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle);
1860 AdoptChild(psBase, psPHand, psCHand);
1862 *phHandle = hHandle;
1864 exit_ok:
1865 if (HANDLES_BATCHED(psBase))
1866 {
1867 psBase->ui32BatchHandAllocFailures--;
1868 }
1870 return PVRSRV_OK;
1871 }
1873 /*!
1874 ******************************************************************************
1876 @Function PVRSRVFindHandle
1878 @Description Find handle corresponding to a resource pointer
1880 @Input phHandle - location for returned handle
1881 pvData - pointer to resource to be associated with the handle
1882 eType - the type of resource
1884 @Output phHandle - points to handle
1886 @Return Error code or PVRSRV_OK
1888 ******************************************************************************/
1889 #if defined (SUPPORT_SID_INTERFACE)
1890 PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType)
1891 #else
1892 PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType)
1893 #endif
1894 {
1895 #if defined (SUPPORT_SID_INTERFACE)
1896 IMG_SID hHandle;
1897 #else
1898 IMG_HANDLE hHandle;
1899 #endif
1901 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1903 /* See if there is a handle for this data pointer */
1904 #if defined (SUPPORT_SID_INTERFACE)
1905 hHandle = (IMG_SID) FindHandle(psBase, pvData, eType, IMG_NULL);
1906 #else
1907 hHandle = (IMG_HANDLE) FindHandle(psBase, pvData, eType, IMG_NULL);
1908 #endif
1909 if (hHandle == IMG_NULL)
1910 {
1911 return PVRSRV_ERROR_HANDLE_NOT_FOUND;
1912 }
1914 *phHandle = hHandle;
1916 return PVRSRV_OK;
1917 }
1919 /*!
1920 ******************************************************************************
1922 @Function PVRSRVLookupHandleAnyType
1924 @Description Lookup the data pointer and type corresponding to a handle
1926 @Input ppvData - location to return data pointer
1927 peType - location to return handle type
1928 hHandle - handle from client
1930 @Output ppvData - points to the data pointer
1931 peType - points to handle type
1933 @Return Error code or PVRSRV_OK
1935 ******************************************************************************/
1936 #if defined (SUPPORT_SID_INTERFACE)
1937 PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_SID hHandle)
1938 #else
1939 PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_HANDLE hHandle)
1940 #endif
1941 {
1942 struct sHandle *psHandle;
1943 PVRSRV_ERROR eError;
1945 eError = GetHandleStructure(psBase, &psHandle, hHandle, PVRSRV_HANDLE_TYPE_NONE);
1946 if (eError != PVRSRV_OK)
1947 {
1948 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandleAnyType: Error looking up handle (%d)", eError));
1949 #if defined (SUPPORT_SID_INTERFACE)
1950 PVR_DBG_BREAK
1951 #endif
1952 return eError;
1953 }
1955 *ppvData = psHandle->pvData;
1956 *peType = psHandle->eType;
1958 return PVRSRV_OK;
1959 }
1961 /*!
1962 ******************************************************************************
1964 @Function PVRSRVLookupHandle
1966 @Description Lookup the data pointer corresponding to a handle
1968 @Input ppvData - location to return data pointer
1969 hHandle - handle from client
1970 eType - handle type
1972 @Output ppvData - points to the data pointer
1974 @Return Error code or PVRSRV_OK
1976 ******************************************************************************/
1977 #if defined (SUPPORT_SID_INTERFACE)
1978 PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType)
1979 #else
1980 PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
1981 #endif
1982 {
1983 struct sHandle *psHandle;
1984 PVRSRV_ERROR eError;
1986 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1987 #if defined (SUPPORT_SID_INTERFACE)
1988 PVR_ASSERT(hHandle != 0);
1989 #endif
1991 eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1992 if (eError != PVRSRV_OK)
1993 {
1994 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandle: Error looking up handle (%d)", eError));
1995 #if defined (SUPPORT_SID_INTERFACE)
1996 PVR_DBG_BREAK
1997 #endif
1998 return eError;
1999 }
2001 *ppvData = psHandle->pvData;
2003 return PVRSRV_OK;
2004 }
2006 /*!
2007 ******************************************************************************
2009 @Function PVRSRVLookupSubHandle
2011 @Description Lookup the data pointer corresponding to a subhandle
2013 @Input ppvData - location to return data pointer
2014 hHandle - handle from client
2015 eType - handle type
2016 hAncestor - ancestor handle
2018 @Output ppvData - points to the data pointer
2020 @Return Error code or PVRSRV_OK
2022 ******************************************************************************/
2023 #if defined (SUPPORT_SID_INTERFACE)
2024 PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType, IMG_SID hAncestor)
2025 #else
2026 PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hAncestor)
2027 #endif
2028 {
2029 struct sHandle *psPHand;
2030 struct sHandle *psCHand;
2031 PVRSRV_ERROR eError;
2033 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
2034 #if defined (SUPPORT_SID_INTERFACE)
2035 PVR_ASSERT(hHandle != 0);
2036 #endif
2038 eError = GetHandleStructure(psBase, &psCHand, hHandle, eType);
2039 if (eError != PVRSRV_OK)
2040 {
2041 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Error looking up subhandle (%d)", eError));
2042 return eError;
2043 }
2045 /* Look for hAncestor among the handle's ancestors */
2046 for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor; )
2047 {
2048 eError = GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand), PVRSRV_HANDLE_TYPE_NONE);
2049 if (eError != PVRSRV_OK)
2050 {
2051 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Subhandle doesn't belong to given ancestor"));
2052 return PVRSRV_ERROR_INVALID_SUBHANDLE;
2053 }
2054 }
2056 *ppvData = psCHand->pvData;
2058 return PVRSRV_OK;
2059 }
2061 /*!
2062 ******************************************************************************
2064 @Function PVRSRVGetParentHandle
2066 @Description Lookup the parent of a handle
2068 @Input phParent - location for returning parent handle
2069 hHandle - handle for which the parent handle is required
2070 eType - handle type
2071 hParent - parent handle
2073 @Output *phParent - parent handle, or IMG_NULL if there is no parent
2075 @Return Error code or PVRSRV_OK. Note that not having a parent is
2076 not regarded as an error.
2078 ******************************************************************************/
2079 #if defined (SUPPORT_SID_INTERFACE)
2080 PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phParent, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType)
2081 #else
2082 PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *phParent, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
2083 #endif
2084 {
2085 struct sHandle *psHandle;
2086 PVRSRV_ERROR eError;
2088 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
2090 eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
2091 if (eError != PVRSRV_OK)
2092 {
2093 PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetParentHandle: Error looking up subhandle (%d)", eError));
2094 return eError;
2095 }
2097 *phParent = ParentHandle(psHandle);
2099 return PVRSRV_OK;
2100 }
2102 /*!
2103 ******************************************************************************
2105 @Function PVRSRVLookupAndReleaseHandle
2107 @Description Lookup the data pointer corresponding to a handle
2109 @Input ppvData - location to return data pointer
2110 hHandle - handle from client
2111 eType - handle type
2112 eFlag - lookup flags
2114 @Output ppvData - points to the data pointer
2116 @Return Error code or PVRSRV_OK
2118 ******************************************************************************/
2119 #if defined (SUPPORT_SID_INTERFACE)
2120 PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType)
2121 #else
2122 PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
2123 #endif
2124 {
2125 struct sHandle *psHandle;
2126 PVRSRV_ERROR eError;
2128 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
2130 eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
2131 if (eError != PVRSRV_OK)
2132 {
2133 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupAndReleaseHandle: Error looking up handle (%d)", eError));
2134 #if defined (SUPPORT_SID_INTERFACE)
2135 PVR_DBG_BREAK
2136 #endif
2137 return eError;
2138 }
2140 *ppvData = psHandle->pvData;
2142 eError = FreeHandle(psBase, psHandle);
2144 return eError;
2145 }
2147 /*!
2148 ******************************************************************************
2150 @Function PVRSRVReleaseHandle
2152 @Description Release a handle that is no longer needed
2154 @Input hHandle - handle from client
2155 eType - handle type
2157 @Return Error code or PVRSRV_OK
2159 ******************************************************************************/
2160 #if defined (SUPPORT_SID_INTERFACE)
2161 PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType)
2162 #else
2163 PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
2164 #endif
2165 {
2166 struct sHandle *psHandle;
2167 PVRSRV_ERROR eError;
2169 PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
2171 eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
2172 if (eError != PVRSRV_OK)
2173 {
2174 PVR_DPF((PVR_DBG_ERROR, "PVRSRVReleaseHandle: Error looking up handle (%d)", eError));
2175 return eError;
2176 }
2178 eError = FreeHandle(psBase, psHandle);
2180 return eError;
2181 }
2183 /*!
2184 ******************************************************************************
2186 @Function PVRSRVNewHandleBatch
2188 @Description Start a new handle batch
2190 @Input psBase - handle base
2191 @Input ui32BatchSize - handle batch size
2193 @Return Error code or PVRSRV_OK
2195 ******************************************************************************/
2196 PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32BatchSize)
2197 {
2198 PVRSRV_ERROR eError;
2200 if (HANDLES_BATCHED(psBase))
2201 {
2202 PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: There is a handle batch already in use (size %u)", psBase->ui32HandBatchSize));
2203 return PVRSRV_ERROR_HANDLE_BATCH_IN_USE;
2204 }
2206 if (ui32BatchSize == 0)
2207 {
2208 PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: Invalid batch size (%u)", ui32BatchSize));
2209 return PVRSRV_ERROR_INVALID_PARAMS;
2210 }
2212 eError = EnsureFreeHandles(psBase, ui32BatchSize);
2213 if (eError != PVRSRV_OK)
2214 {
2215 PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: EnsureFreeHandles failed (error %d)", eError));
2216 return eError;
2217 }
2219 psBase->ui32HandBatchSize = ui32BatchSize;
2221 /* Record current number of handles */
2222 psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount;
2224 PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0);
2226 PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0);
2228 PVR_ASSERT(HANDLES_BATCHED(psBase));
2230 return PVRSRV_OK;
2231 }
2233 /*!
2234 ******************************************************************************
2236 @Function PVRSRVHandleBatchCommitOrRelease
2238 @Description Release a handle batch
2240 @Input psBase - handle base
2241 bCommit - commit handles
2243 @Return none
2245 ******************************************************************************/
2246 static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit)
2247 {
2249 IMG_UINT32 ui32IndexPlusOne;
2250 IMG_BOOL bCommitBatch = bCommit;
2252 if (!HANDLES_BATCHED(psBase))
2253 {
2254 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: There is no handle batch"));
2255 return PVRSRV_ERROR_INVALID_PARAMS;
2257 }
2259 if (psBase->ui32BatchHandAllocFailures != 0)
2260 {
2261 if (bCommit)
2262 {
2263 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Attempting to commit batch with handle allocation failures."));
2264 }
2265 bCommitBatch = IMG_FALSE;
2266 }
2267 /*
2268 * The whole point of batched handles is to avoid handle allocation
2269 * failures.
2270 */
2271 PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit);
2273 ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne;
2274 while(ui32IndexPlusOne != 0)
2275 {
2276 struct sHandle *psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32IndexPlusOne - 1);
2277 IMG_UINT32 ui32NextIndexPlusOne = psHandle->ui32NextIndexPlusOne;
2278 PVR_ASSERT(BATCHED_HANDLE(psHandle));
2280 psHandle->ui32NextIndexPlusOne = 0;
2282 if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
2283 {
2284 PVRSRV_ERROR eError;
2286 /*
2287 * We need a complete free here. If the handle
2288 * is not partially free, set the handle as
2289 * unbatched to avoid a partial free.
2290 */
2291 if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
2292 {
2293 /* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */
2294 SET_UNBATCHED_HANDLE(psHandle); /* PRQA S 4130 */ /* mis-use of enums FIXME*/
2295 }
2297 eError = FreeHandle(psBase, psHandle);
2298 if (eError != PVRSRV_OK)
2299 {
2300 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Error freeing handle (%d)", eError));
2301 }
2302 PVR_ASSERT(eError == PVRSRV_OK);
2303 }
2304 else
2305 {
2306 /* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */
2307 SET_UNBATCHED_HANDLE(psHandle);
2308 }
2310 ui32IndexPlusOne = ui32NextIndexPlusOne;
2311 }
2313 #ifdef DEBUG
2314 if (psBase->ui32TotalHandCountPreBatch != psBase->ui32TotalHandCount)
2315 {
2316 IMG_UINT32 ui32Delta = psBase->ui32TotalHandCount - psBase->ui32TotalHandCountPreBatch;
2318 PVR_ASSERT(psBase->ui32TotalHandCount > psBase->ui32TotalHandCountPreBatch);
2320 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));
2322 }
2323 #endif
2325 psBase->ui32HandBatchSize = 0;
2326 psBase->ui32FirstBatchIndexPlusOne = 0;
2327 psBase->ui32TotalHandCountPreBatch = 0;
2328 psBase->ui32BatchHandAllocFailures = 0;
2330 if (psBase->ui32BatchHandAllocFailures != 0 && bCommit)
2331 {
2332 PVR_ASSERT(!bCommitBatch);
2334 return PVRSRV_ERROR_HANDLE_BATCH_COMMIT_FAILURE;
2335 }
2337 return PVRSRV_OK;
2338 }
2340 /*!
2341 ******************************************************************************
2343 @Function PVRSRVCommitHandleBatch
2345 @Description Commit a handle batch
2347 @Input psBase - handle base
2349 @Return Error code or PVRSRV_OK
2351 ******************************************************************************/
2352 PVRSRV_ERROR PVRSRVCommitHandleBatch(PVRSRV_HANDLE_BASE *psBase)
2353 {
2354 return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE);
2355 }
2357 /*!
2358 ******************************************************************************
2360 @Function PVRSRReleaseHandleBatch
2362 @Description Release a handle batch
2364 @Input psBase - handle base
2366 @Return none
2368 ******************************************************************************/
2369 IMG_VOID PVRSRVReleaseHandleBatch(PVRSRV_HANDLE_BASE *psBase)
2370 {
2371 (IMG_VOID) PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE);
2372 }
2374 /*!
2375 ******************************************************************************
2377 @Function PVRSRVSetMaxHandle
2379 @Description Set maximum handle number for given handle base
2381 @Input psBase - pointer to handle base structure
2382 ui32MaxHandle - Maximum handle number
2384 @Return Error code or PVRSRV_OK
2386 ******************************************************************************/
2387 PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHandle)
2388 {
2389 IMG_UINT32 ui32MaxHandleRounded;
2391 if (HANDLES_BATCHED(psBase))
2392 {
2393 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set whilst in batch mode"));
2394 return PVRSRV_ERROR_INVALID_PARAMS;
2395 }
2397 /* Validate the limit */
2398 if (ui32MaxHandle == 0 || ui32MaxHandle > DEFAULT_MAX_HANDLE)
2399 {
2400 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit must be between %u and %u, inclusive", 0, DEFAULT_MAX_HANDLE));
2402 return PVRSRV_ERROR_INVALID_PARAMS;
2403 }
2405 /* The limit can only be set if no handles have been allocated */
2406 if (psBase->ui32TotalHandCount != 0)
2407 {
2408 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set because handles have already been allocated"));
2410 return PVRSRV_ERROR_INVALID_PARAMS;
2411 }
2413 ui32MaxHandleRounded = ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(ui32MaxHandle);
2415 /*
2416 * Allow the maximum number of handles to be reduced, but never to
2417 * zero.
2418 */
2419 if (ui32MaxHandleRounded != 0 && ui32MaxHandleRounded < psBase->ui32MaxIndexPlusOne)
2420 {
2421 psBase->ui32MaxIndexPlusOne = ui32MaxHandleRounded;
2422 }
2424 PVR_ASSERT(psBase->ui32MaxIndexPlusOne != 0);
2425 PVR_ASSERT(psBase->ui32MaxIndexPlusOne <= DEFAULT_MAX_INDEX_PLUS_ONE);
2426 PVR_ASSERT((psBase->ui32MaxIndexPlusOne % HANDLE_BLOCK_SIZE) == 0);
2428 return PVRSRV_OK;
2429 }
2431 /*!
2432 ******************************************************************************
2434 @Function PVRSRVGetMaxHandle
2436 @Description Get maximum handle number for given handle base
2438 @Input psBase - pointer to handle base structure
2440 @Output Maximum handle number, or 0 if handle limits not
2441 supported.
2443 @Return Error code or PVRSRV_OK
2445 ******************************************************************************/
2446 IMG_UINT32 PVRSRVGetMaxHandle(PVRSRV_HANDLE_BASE *psBase)
2447 {
2448 return psBase->ui32MaxIndexPlusOne;
2449 }
2451 /*!
2452 ******************************************************************************
2454 @Function PVRSRVEnableHandlePurging
2456 @Description Enable purging for a given handle base
2458 @Input psBase - pointer to handle base structure
2460 @Return Error code or PVRSRV_OK
2462 ******************************************************************************/
2463 PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase)
2464 {
2465 if (psBase->bPurgingEnabled)
2466 {
2467 PVR_DPF((PVR_DBG_WARNING, "PVRSRVEnableHandlePurging: Purging already enabled"));
2468 return PVRSRV_OK;
2469 }
2471 /* Purging can only be enabled if no handles have been allocated */
2472 if (psBase->ui32TotalHandCount != 0)
2473 {
2474 PVR_DPF((PVR_DBG_ERROR, "PVRSRVEnableHandlePurging: Handles have already been allocated"));
2475 return PVRSRV_ERROR_INVALID_PARAMS;
2476 }
2478 psBase->bPurgingEnabled = IMG_TRUE;
2480 return PVRSRV_OK;
2481 }
2483 /*!
2484 ******************************************************************************
2486 @Function PVRSRVPurgeHandles
2488 @Description Purge handles for a given handle base
2490 @Input psBase - pointer to handle base structure
2492 @Return Error code or PVRSRV_OK
2494 ******************************************************************************/
2495 PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase)
2496 {
2497 IMG_UINT32 ui32BlockIndex;
2498 IMG_UINT32 ui32NewHandCount;
2500 if (!psBase->bPurgingEnabled)
2501 {
2502 PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Purging not enabled for this handle base"));
2503 return PVRSRV_ERROR_NOT_SUPPORTED;
2504 }
2506 if (HANDLES_BATCHED(psBase))
2507 {
2508 PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Purging not allowed whilst in batch mode"));
2509 return PVRSRV_ERROR_INVALID_PARAMS;
2510 }
2512 PVR_ASSERT((psBase->ui32TotalHandCount % HANDLE_BLOCK_SIZE) == 0);
2514 for (ui32BlockIndex = INDEX_TO_BLOCK_INDEX(psBase->ui32TotalHandCount); ui32BlockIndex != 0; ui32BlockIndex--)
2515 {
2516 if (psBase->psHandleArray[ui32BlockIndex - 1].ui32FreeHandBlockCount != HANDLE_BLOCK_SIZE)
2517 {
2518 break;
2519 }
2520 }
2521 ui32NewHandCount = BLOCK_INDEX_TO_INDEX(ui32BlockIndex);
2523 /*
2524 * Check for a suitable decrease in the handle count.
2525 */
2526 if (ui32NewHandCount <= (psBase->ui32TotalHandCount/2))
2527 {
2528 PVRSRV_ERROR eError;
2530 // PVR_TRACE((" PVRSRVPurgeHandles: reducing number of handles from %u to %u", psBase->ui32TotalHandCount, ui32NewHandCount));
2532 eError = ReallocHandleArray(psBase, ui32NewHandCount);
2533 if (eError != PVRSRV_OK)
2534 {
2535 return eError;
2536 }
2537 }
2539 return PVRSRV_OK;
2540 }
2542 /*!
2543 ******************************************************************************
2545 @Function PVRSRVAllocHandleBase
2547 @Description Allocate a handle base structure for a process
2549 @Input ppsBase - pointer to handle base structure pointer
2551 @Output ppsBase - points to handle base structure pointer
2553 @Return Error code or PVRSRV_OK
2555 ******************************************************************************/
2556 PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase)
2557 {
2558 PVRSRV_HANDLE_BASE *psBase;
2559 IMG_HANDLE hBlockAlloc;
2560 PVRSRV_ERROR eError;
2562 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
2563 sizeof(*psBase),
2564 (IMG_PVOID *)&psBase,
2565 &hBlockAlloc,
2566 "Handle Base");
2567 if (eError != PVRSRV_OK)
2568 {
2569 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't allocate handle base (%d)", eError));
2570 return eError;
2571 }
2572 OSMemSet(psBase, 0, sizeof(*psBase));
2574 /* Create hash table */
2575 psBase->psHashTab = HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, sizeof(HAND_KEY), HASH_Func_Default, HASH_Key_Comp_Default);
2576 if (psBase->psHashTab == IMG_NULL)
2577 {
2578 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't create data pointer hash table\n"));
2579 (IMG_VOID)PVRSRVFreeHandleBase(psBase);
2580 return PVRSRV_ERROR_UNABLE_TO_CREATE_HASH_TABLE;
2581 }
2583 psBase->hBaseBlockAlloc = hBlockAlloc;
2585 psBase->ui32MaxIndexPlusOne = DEFAULT_MAX_INDEX_PLUS_ONE;
2587 *ppsBase = psBase;
2589 return PVRSRV_OK;
2590 }
2592 /*!
2593 ******************************************************************************
2595 @Function PVRSRVFreeHandleBase
2597 @Description Free a handle base structure
2599 @Input psBase - pointer to handle base structure
2601 @Return Error code or PVRSRV_OK
2603 ******************************************************************************/
2604 PVRSRV_ERROR PVRSRVFreeHandleBase(PVRSRV_HANDLE_BASE *psBase)
2605 {
2606 PVRSRV_ERROR eError;
2608 PVR_ASSERT(psBase != gpsKernelHandleBase);
2610 eError = FreeHandleBase(psBase);
2611 if (eError != PVRSRV_OK)
2612 {
2613 PVR_DPF((PVR_DBG_ERROR, "PVRSRVFreeHandleBase: FreeHandleBase failed (%d)", eError));
2614 }
2616 return eError;
2617 }
2619 /*!
2620 ******************************************************************************
2622 @Function PVRSRVHandleInit
2624 @Description Initialise handle management
2626 @Return Error code or PVRSRV_OK
2628 ******************************************************************************/
2629 PVRSRV_ERROR PVRSRVHandleInit(IMG_VOID)
2630 {
2631 PVRSRV_ERROR eError;
2633 PVR_ASSERT(gpsKernelHandleBase == IMG_NULL);
2635 eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase);
2636 if (eError != PVRSRV_OK)
2637 {
2638 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleInit: PVRSRVAllocHandleBase failed (%d)", eError));
2639 goto error;
2640 }
2642 eError = PVRSRVEnableHandlePurging(gpsKernelHandleBase);
2643 if (eError != PVRSRV_OK)
2644 {
2645 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleInit: PVRSRVEnableHandlePurging failed (%d)", eError));
2646 goto error;
2647 }
2649 return PVRSRV_OK;
2650 error:
2651 (IMG_VOID) PVRSRVHandleDeInit();
2652 return eError;
2653 }
2655 /*!
2656 ******************************************************************************
2658 @Function PVRSRVHandleDeInit
2660 @Description De-initialise handle management
2662 @Return Error code or PVRSRV_OK
2664 ******************************************************************************/
2665 PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID)
2666 {
2667 PVRSRV_ERROR eError = PVRSRV_OK;
2669 if (gpsKernelHandleBase != IMG_NULL)
2670 {
2671 eError = FreeHandleBase(gpsKernelHandleBase);
2672 if (eError == PVRSRV_OK)
2673 {
2674 gpsKernelHandleBase = IMG_NULL;
2675 }
2676 else
2677 {
2678 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleDeInit: FreeHandleBase failed (%d)", eError));
2679 }
2680 }
2682 return eError;
2683 }
2684 #else
2685 /* disable warning about empty module */
2686 #endif /* #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) */
2687 /******************************************************************************
2688 End of file (handle.c)
2689 ******************************************************************************/