HGCMObjects.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
/** @file
*
* HGCM (Host-Guest Communication Manager):
* HGCMObjects - Host-Guest Communication Manager objects
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
#include "Logging.h"
#include "HGCMObjects.h"
#include <string.h>
#include <VBox/err.h>
static RTCRITSECT g_critsect;
/* There are internal handles, which are not saved,
* and client handles, which are saved.
* They use different range of values:
* 1..7FFFFFFF for clients,
* 0x80000001..0xFFFFFFFF for other handles.
*/
static uint32_t volatile g_u32InternalHandleCount;
static uint32_t volatile g_u32ClientHandleCount;
static PAVLULNODECORE g_pTree;
DECLINLINE(int) hgcmObjEnter (void)
{
return RTCritSectEnter (&g_critsect);
}
DECLINLINE(void) hgcmObjLeave (void)
{
RTCritSectLeave (&g_critsect);
}
int hgcmObjInit (void)
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmObjInit\n"));
g_u32InternalHandleCount = 0x80000000;
g_u32ClientHandleCount = 0;
g_pTree = NULL;
rc = RTCritSectInit (&g_critsect);
LogFlow(("MAIN::hgcmObjInit: rc = %Rrc\n", rc));
return rc;
}
void hgcmObjUninit (void)
{
if (RTCritSectIsInitialized (&g_critsect))
{
RTCritSectDelete (&g_critsect);
}
}
uint32_t hgcmObjMake (HGCMObject *pObject, uint32_t u32HandleIn)
{
int handle = 0;
LogFlow(("MAIN::hgcmObjGenerateHandle: pObject %p\n", pObject));
int rc = hgcmObjEnter ();
if (RT_SUCCESS(rc))
{
ObjectAVLCore *pCore = &pObject->Core;
/* Generate a new handle value. */
uint32_t volatile *pu32HandleCountSource = pObject->Type () == HGCMOBJ_CLIENT?
&g_u32ClientHandleCount:
&g_u32InternalHandleCount;
uint32_t u32Start = *pu32HandleCountSource;
for (;;)
{
uint32_t Key;
if (u32HandleIn == 0)
{
Key = ASMAtomicIncU32 (pu32HandleCountSource);
if (Key == u32Start)
{
/* Rollover. Something is wrong. */
AssertReleaseFailed ();
break;
}
/* 0 and 0x80000000 are not valid handles. */
if ((Key & 0x7FFFFFFF) == 0)
{
/* Over the invalid value, reinitialize the source. */
*pu32HandleCountSource = pObject->Type () == HGCMOBJ_CLIENT?
0:
0x80000000;
continue;
}
}
else
{
Key = u32HandleIn;
}
/* Insert object to AVL tree. */
pCore->AvlCore.Key = Key;
bool bRC = RTAvlULInsert(&g_pTree, &pCore->AvlCore);
/* Could not insert a handle. */
if (!bRC)
{
if (u32HandleIn == 0)
{
/* Try another generated handle. */
continue;
}
else
{
/* Could not use the specified handle. */
break;
}
}
/* Initialize backlink. */
pCore->pSelf = pObject;
/* Reference the object for time while it resides in the tree. */
pObject->Reference ();
/* Store returned handle. */
handle = Key;
Log(("Object key inserted 0x%08X\n", Key));
break;
}
hgcmObjLeave ();
}
else
{
AssertReleaseMsgFailed (("MAIN::hgcmObjGenerateHandle: Failed to acquire object pool semaphore"));
}
LogFlow(("MAIN::hgcmObjGenerateHandle: handle = 0x%08X, rc = %Rrc, return void\n", handle, rc));
return handle;
}
uint32_t hgcmObjGenerateHandle (HGCMObject *pObject)
{
return hgcmObjMake (pObject, 0);
}
uint32_t hgcmObjAssignHandle (HGCMObject *pObject, uint32_t u32Handle)
{
return hgcmObjMake (pObject, u32Handle);
}
void hgcmObjDeleteHandle (uint32_t handle)
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmObjDeleteHandle: handle 0x%08X\n", handle));
if (handle)
{
rc = hgcmObjEnter ();
if (RT_SUCCESS(rc))
{
ObjectAVLCore *pCore = (ObjectAVLCore *)RTAvlULRemove (&g_pTree, handle);
if (pCore)
{
AssertRelease(pCore->pSelf);
pCore->pSelf->Dereference ();
}
hgcmObjLeave ();
}
else
{
AssertReleaseMsgFailed (("Failed to acquire object pool semaphore, rc = %Rrc", rc));
}
}
LogFlow(("MAIN::hgcmObjDeleteHandle: rc = %Rrc, return void\n", rc));
return;
}
HGCMObject *hgcmObjReference (uint32_t handle, HGCMOBJ_TYPE enmObjType)
{
LogFlow(("MAIN::hgcmObjReference: handle 0x%08X\n", handle));
HGCMObject *pObject = NULL;
if ((handle & 0x7FFFFFFF) == 0)
{
return pObject;
}
int rc = hgcmObjEnter ();
if (RT_SUCCESS(rc))
{
ObjectAVLCore *pCore = (ObjectAVLCore *)RTAvlULGet (&g_pTree, handle);
Assert(!pCore || (pCore->pSelf && pCore->pSelf->Type() == enmObjType));
if ( pCore
&& pCore->pSelf
&& pCore->pSelf->Type() == enmObjType)
{
pObject = pCore->pSelf;
AssertRelease(pObject);
pObject->Reference ();
}
hgcmObjLeave ();
}
else
{
AssertReleaseMsgFailed (("Failed to acquire object pool semaphore, rc = %Rrc", rc));
}
LogFlow(("MAIN::hgcmObjReference: return pObject %p\n", pObject));
return pObject;
}
void hgcmObjDereference (HGCMObject *pObject)
{
LogFlow(("MAIN::hgcmObjDereference: pObject %p\n", pObject));
AssertRelease(pObject);
pObject->Dereference ();
LogFlow(("MAIN::hgcmObjDereference: return\n"));
}
uint32_t hgcmObjQueryHandleCount ()
{
return g_u32ClientHandleCount;
}
void hgcmObjSetHandleCount (uint32_t u32ClientHandleCount)
{
Assert(g_u32ClientHandleCount <= u32ClientHandleCount);
int rc = hgcmObjEnter ();
if (RT_SUCCESS(rc))
{
if (g_u32ClientHandleCount <= u32ClientHandleCount)
g_u32ClientHandleCount = u32ClientHandleCount;
hgcmObjLeave ();
}
}