/* $Id: HGCMObjects.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */ /** @file * HGCMObjects - Host-Guest Communication Manager objects */ /* * Copyright (C) 2006-2022 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 LOG_GROUP_HGCM #include "LoggingNew.h" #include "HGCMObjects.h" #include #include 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 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->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, 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 *)RTAvlU32Remove(&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)); } 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 rc = hgcmObjEnter(); if (RT_SUCCESS(rc)) { 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, 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(); } }