blob: eb73166bb32c6fe7c11bd0df9b3a78065a4bfc99 [file] [log] [blame]
/**********************************************************************
*
* 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. <gpl-support@imgtec.com>
* 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;
}