diff options
Diffstat (limited to 'src/VBox/Main/src-client/HGCMObjects.cpp')
-rw-r--r-- | src/VBox/Main/src-client/HGCMObjects.cpp | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/src/VBox/Main/src-client/HGCMObjects.cpp b/src/VBox/Main/src-client/HGCMObjects.cpp new file mode 100644 index 00000000..0b668618 --- /dev/null +++ b/src/VBox/Main/src-client/HGCMObjects.cpp @@ -0,0 +1,286 @@ +/* $Id: HGCMObjects.cpp $ */ +/** @file + * HGCMObjects - Host-Guest Communication Manager objects + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * 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, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_GROUP LOG_GROUP_HGCM +#include "LoggingNew.h" + +#include "HGCMObjects.h" + +#include <iprt/string.h> +#include <iprt/errcore.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 PAVLU32NODECORE g_pTree; + + +DECLINLINE(int) hgcmObjEnter(void) +{ + return RTCritSectEnter(&g_critsect); +} + +DECLINLINE(void) hgcmObjLeave(void) +{ + RTCritSectLeave(&g_critsect); +} + +int hgcmObjInit(void) +{ + LogFlow(("MAIN::hgcmObjInit\n")); + + g_u32InternalHandleCount = 0x80000000; + g_u32ClientHandleCount = 0; + g_pTree = NULL; + + int vrc = RTCritSectInit(&g_critsect); + + LogFlow(("MAIN::hgcmObjInit: vrc = %Rrc\n", vrc)); + + return vrc; +} + +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 vrc = hgcmObjEnter(); + + if (RT_SUCCESS(vrc)) + { + ObjectAVLCore *pCore = &pObject->m_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: + UINT32_C(0x80000000); + continue; + } + } + else + { + Key = u32HandleIn; + } + + /* Insert object to AVL tree. */ + pCore->AvlCore.Key = Key; + + bool fRC = RTAvlU32Insert(&g_pTree, &pCore->AvlCore); + + /* Could not insert a handle. */ + if (!fRC) + { + if (u32HandleIn == 0) + { + /* Try another generated handle. */ + continue; + } + /* 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, vrc = %Rrc, return void\n", handle, vrc)); + + 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 vrc = VINF_SUCCESS; + + LogFlow(("MAIN::hgcmObjDeleteHandle: handle 0x%08X\n", handle)); + + if (handle) + { + vrc = hgcmObjEnter(); + + if (RT_SUCCESS(vrc)) + { + ObjectAVLCore *pCore = (ObjectAVLCore *)RTAvlU32Remove(&g_pTree, handle); + + if (pCore) + { + AssertRelease(pCore->pSelf); + + pCore->pSelf->Dereference(); + } + + hgcmObjLeave(); + } + else + { + AssertReleaseMsgFailed(("Failed to acquire object pool semaphore, vrc = %Rrc", vrc)); + } + } + + LogFlow(("MAIN::hgcmObjDeleteHandle: vrc = %Rrc, return void\n", vrc)); +} + +HGCMObject *hgcmObjReference (uint32_t handle, HGCMOBJ_TYPE enmObjType) +{ + LogFlow(("MAIN::hgcmObjReference: handle 0x%08X\n", handle)); + + HGCMObject *pObject = NULL; + + if ((handle & UINT32_C(0x7FFFFFFF)) == 0) + { + return pObject; + } + + int vrc = hgcmObjEnter(); + + if (RT_SUCCESS(vrc)) + { + ObjectAVLCore *pCore = (ObjectAVLCore *)RTAvlU32Get(&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, vrc = %Rrc", vrc)); + } + + 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 vrc = hgcmObjEnter(); + + if (RT_SUCCESS(vrc)) + { + if (g_u32ClientHandleCount <= u32ClientHandleCount) + g_u32ClientHandleCount = u32ClientHandleCount; + hgcmObjLeave(); + } +} |