/********************************************************************** * * Copyright (C) Imagination Technologies Ltd. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful but, except * as otherwise stated in writing, without any warranty; without even the * implied warranty of merchantability or fitness for a particular purpose. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * * Contact Information: * Imagination Technologies Ltd. * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK * ******************************************************************************/ #include "services_headers.h" #include "resman.h" #include "handle.h" #include "perproc.h" #include "osperproc.h" #if defined(TTRACE) #include "ttrace.h" #endif #define HASH_TAB_INIT_SIZE 32 static HASH_TABLE *psHashTab = IMG_NULL; static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) { PVRSRV_ERROR eError; IMG_UINTPTR_T uiPerProc; PVR_ASSERT(psPerProc != IMG_NULL); if (psPerProc == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: invalid parameter")); return PVRSRV_ERROR_INVALID_PARAMS; } uiPerProc = HASH_Remove(psHashTab, (IMG_UINTPTR_T)psPerProc->ui32PID); if (uiPerProc == 0) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't find process in per-process data hash table")); PVR_ASSERT(psPerProc->ui32PID == 0); } else { PVR_ASSERT((PVRSRV_PER_PROCESS_DATA *)uiPerProc == psPerProc); PVR_ASSERT(((PVRSRV_PER_PROCESS_DATA *)uiPerProc)->ui32PID == psPerProc->ui32PID); } if (psPerProc->psHandleBase != IMG_NULL) { eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free handle base for process (%d)", eError)); return eError; } } if (psPerProc->hPerProcData != IMG_NULL) { eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, psPerProc->hPerProcData, PVRSRV_HANDLE_TYPE_PERPROC_DATA); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't release per-process data handle (%d)", eError)); return eError; } } eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: OSPerProcessPrivateDataDeInit failed (%d)", eError)); return eError; } eError = OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), psPerProc, psPerProc->hBlockAlloc); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free per-process data (%d)", eError)); return eError; } return PVRSRV_OK; } PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(IMG_UINT32 ui32PID) { PVRSRV_PER_PROCESS_DATA *psPerProc; PVR_ASSERT(psHashTab != IMG_NULL); psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); return psPerProc; } PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) { PVRSRV_PER_PROCESS_DATA *psPerProc; IMG_HANDLE hBlockAlloc; PVRSRV_ERROR eError = PVRSRV_OK; if (psHashTab == IMG_NULL) { return PVRSRV_ERROR_INIT_FAILURE; } psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); if (psPerProc == IMG_NULL) { eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), (IMG_PVOID *)&psPerProc, &hBlockAlloc, "Per Process Data"); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate per-process data (%d)", eError)); return eError; } OSMemSet(psPerProc, 0, sizeof(*psPerProc)); psPerProc->hBlockAlloc = hBlockAlloc; if (!HASH_Insert(psHashTab, (IMG_UINTPTR_T)ui32PID, (IMG_UINTPTR_T)psPerProc)) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't insert per-process data into hash table")); eError = PVRSRV_ERROR_INSERT_HASH_TABLE_DATA_FAILED; goto failure; } psPerProc->ui32PID = ui32PID; psPerProc->ui32RefCount = 0; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if (ui32Flags == SRV_FLAGS_PDUMP_ACTIVE) { psPerProc->bPDumpActive = IMG_TRUE; } #else PVR_UNREFERENCED_PARAMETER(ui32Flags); #endif eError = OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: OSPerProcessPrivateDataInit failed (%d)", eError)); goto failure; } eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, &psPerProc->hPerProcData, psPerProc, PVRSRV_HANDLE_TYPE_PERPROC_DATA, PVRSRV_HANDLE_ALLOC_FLAG_NONE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate handle for per-process data (%d)", eError)); goto failure; } eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate handle base for process (%d)", eError)); goto failure; } eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't set handle options (%d)", eError)); goto failure; } eError = PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't register with the resource manager")); goto failure; } #if defined (TTRACE) PVRSRVTimeTraceBufferCreate(ui32PID); #endif } psPerProc->ui32RefCount++; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d", ui32PID, psPerProc->ui32RefCount)); return eError; failure: (IMG_VOID)FreePerProcessData(psPerProc); return eError; } IMG_VOID PVRSRVPerProcessDataDisconnect(IMG_UINT32 ui32PID) { PVRSRV_ERROR eError; PVRSRV_PER_PROCESS_DATA *psPerProc; PVR_ASSERT(psHashTab != IMG_NULL); psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); if (psPerProc == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataDealloc: Couldn't locate per-process data for PID %u", ui32PID)); } else { psPerProc->ui32RefCount--; if (psPerProc->ui32RefCount == 0) { PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVPerProcessDataDisconnect: " "Last close from process 0x%x received", ui32PID)); #if defined (TTRACE) PVRSRVTimeTraceBufferDestroy(ui32PID); #endif PVRSRVResManDisconnect(psPerProc->hResManContext, IMG_FALSE); eError = FreePerProcessData(psPerProc); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataDisconnect: Error freeing per-process data")); } } } eError = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataDisconnect: Purge of global handle pool failed (%d)", eError)); } } PVRSRV_ERROR PVRSRVPerProcessDataInit(IMG_VOID) { PVR_ASSERT(psHashTab == IMG_NULL); psHashTab = HASH_Create(HASH_TAB_INIT_SIZE); if (psHashTab == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataInit: Couldn't create per-process data hash table")); return PVRSRV_ERROR_UNABLE_TO_CREATE_HASH_TABLE; } return PVRSRV_OK; } PVRSRV_ERROR PVRSRVPerProcessDataDeInit(IMG_VOID) { if (psHashTab != IMG_NULL) { HASH_Delete(psHashTab); psHashTab = IMG_NULL; } return PVRSRV_OK; }