3
* HGCM (Host-Guest Communication Manager)
7
* Copyright (C) 2006-2007 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18
#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
22
#include "HGCMThread.h"
25
#include <VBox/hgcmsvc.h>
26
#include <VBox/vmm/ssm.h>
29
#include <iprt/alloc.h>
30
#include <iprt/alloca.h>
32
#include <iprt/critsect.h>
35
#include <iprt/param.h>
36
#include <iprt/path.h>
37
#include <iprt/string.h>
38
#include <iprt/semaphore.h>
39
#include <iprt/thread.h>
41
#include <VBox/VMMDev.h>
44
* A service gets one thread, which synchronously delivers messages to
45
* the service. This is good for serialization.
47
* Some services may want to process messages asynchronously, and will want
48
* a next message to be delivered, while a previous message is still being
51
* The dedicated service thread delivers a next message when service
52
* returns after fetching a previous one. The service will call a message
53
* completion callback when message is actually processed. So returning
54
* from the service call means only that the service is processing message.
56
* 'Message processed' condition is indicated by service, which call the
57
* callback, even if the callback is called synchronously in the dedicated
60
* This message completion callback is only valid for Call requests.
61
* Connect and Disconnect are processed synchronously by the service.
65
/* The maximum allowed size of a service name in bytes. */
66
#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
68
struct _HGCMSVCEXTHANDLEDATA
71
/* The service name follows. */
74
/** Internal helper service object. HGCM code would use it to
75
* hold information about services and communicate with services.
76
* The HGCMService is an (in future) abstract class that implements
77
* common functionality. There will be derived classes for specific
84
VBOXHGCMSVCHELPERS m_svcHelpers;
86
static HGCMService *sm_pSvcListHead;
87
static HGCMService *sm_pSvcListTail;
89
static int sm_cServices;
91
HGCMTHREADHANDLE m_thread;
92
friend DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
94
uint32_t volatile m_u32RefCnt;
96
HGCMService *m_pSvcNext;
97
HGCMService *m_pSvcPrev;
100
char *m_pszSvcLibrary;
103
PFNVBOXHGCMSVCLOAD m_pfnLoad;
105
VBOXHGCMSVCFNTABLE m_fntable;
108
int m_cClientsAllocated;
110
uint32_t *m_paClientIds;
112
#ifdef VBOX_WITH_CRHGSMI
113
uint32_t m_cHandleAcquires;
116
HGCMSVCEXTHANDLE m_hExtension;
118
int loadServiceDLL (void);
119
void unloadServiceDLL (void);
122
* Main HGCM thread methods.
124
int instanceCreate (const char *pszServiceLibrary, const char *pszServiceName);
125
void instanceDestroy (void);
127
int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
128
int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
133
static DECLCALLBACK(void) svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc);
134
static DECLCALLBACK(void) svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId);
139
* Main HGCM thread methods.
141
static int LoadService (const char *pszServiceLibrary, const char *pszServiceName);
142
void UnloadService (void);
144
static void UnloadAll (void);
146
static int ResolveService (HGCMService **ppsvc, const char *pszServiceName);
147
void ReferenceService (void);
148
void ReleaseService (void);
150
static void Reset (void);
152
static int SaveState (PSSMHANDLE pSSM);
153
static int LoadState (PSSMHANDLE pSSM);
155
int CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn);
156
int DisconnectClient (uint32_t u32ClientId, bool fFromService);
158
int HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
160
#ifdef VBOX_WITH_CRHGSMI
161
int HandleAcquired();
162
int HandleReleased();
163
int HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion);
166
uint32_t SizeOfClient (void) { return m_fntable.cbClient; };
168
int RegisterExtension (HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
169
void UnregisterExtension (HGCMSVCEXTHANDLE handle);
172
* The service thread methods.
175
int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
179
class HGCMClient: public HGCMObject
182
HGCMClient () : HGCMObject(HGCMOBJ_CLIENT), pService(NULL),
186
int Init (HGCMService *pSvc);
188
/** Service that the client is connected to. */
189
HGCMService *pService;
191
/** Client specific data. */
195
HGCMClient::~HGCMClient ()
197
if (pService->SizeOfClient () > 0)
201
int HGCMClient::Init (HGCMService *pSvc)
205
if (pService->SizeOfClient () > 0)
207
pvData = RTMemAllocZ (pService->SizeOfClient ());
211
return VERR_NO_MEMORY;
219
#define HGCM_CLIENT_DATA(pService, pClient) (pClient->pvData)
223
HGCMService *HGCMService::sm_pSvcListHead = NULL;
224
HGCMService *HGCMService::sm_pSvcListTail = NULL;
225
int HGCMService::sm_cServices = 0;
227
HGCMService::HGCMService ()
234
m_pszSvcLibrary (NULL),
235
m_hLdrMod (NIL_RTLDRMOD),
238
m_cClientsAllocated (0),
239
m_paClientIds (NULL),
240
#ifdef VBOX_WITH_CRHGSMI
241
m_cHandleAcquires (0),
245
memset (&m_fntable, 0, sizeof (m_fntable));
249
static bool g_fResetting = false;
250
static bool g_fSaveState = false;
253
/** Helper function to load a local service DLL.
257
int HGCMService::loadServiceDLL (void)
259
LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
261
if (m_pszSvcLibrary == NULL)
263
return VERR_INVALID_PARAMETER;
266
RTERRINFOSTATIC ErrInfo;
267
RTErrInfoInitStatic (&ErrInfo);
269
int rc = SUPR3HardenedLdrLoadAppPriv (m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
273
LogFlowFunc(("successfully loaded the library.\n"));
277
rc = RTLdrGetSymbol (m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
279
if (RT_FAILURE(rc) || !m_pfnLoad)
281
Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
285
/* m_pfnLoad was NULL */
286
rc = VERR_SYMBOL_NOT_FOUND;
292
memset (&m_fntable, 0, sizeof (m_fntable));
294
m_fntable.cbSize = sizeof (m_fntable);
295
m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
296
m_fntable.pHelpers = &m_svcHelpers;
298
rc = m_pfnLoad (&m_fntable);
300
LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc));
304
if ( m_fntable.pfnUnload == NULL
305
|| m_fntable.pfnConnect == NULL
306
|| m_fntable.pfnDisconnect == NULL
307
|| m_fntable.pfnCall == NULL
310
Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
312
rc = VERR_INVALID_PARAMETER;
314
if (m_fntable.pfnUnload)
316
m_fntable.pfnUnload (m_fntable.pvService);
324
LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc - %s. The service will be not available.\n",
325
m_pszSvcLibrary, rc, ErrInfo.Core.pszMsg));
326
m_hLdrMod = NIL_RTLDRMOD;
337
/** Helper function to free a local service DLL.
341
void HGCMService::unloadServiceDLL (void)
345
RTLdrClose (m_hLdrMod);
348
memset (&m_fntable, 0, sizeof (m_fntable));
350
m_hLdrMod = NIL_RTLDRMOD;
354
* Messages processed by service threads. These threads only call the service entry points.
357
#define SVC_MSG_LOAD (0) /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
358
#define SVC_MSG_UNLOAD (1) /* call pfnUnload and unload the service library. */
359
#define SVC_MSG_CONNECT (2) /* pfnConnect */
360
#define SVC_MSG_DISCONNECT (3) /* pfnDisconnect */
361
#define SVC_MSG_GUESTCALL (4) /* pfnGuestCall */
362
#define SVC_MSG_HOSTCALL (5) /* pfnHostCall */
363
#define SVC_MSG_LOADSTATE (6) /* pfnLoadState. */
364
#define SVC_MSG_SAVESTATE (7) /* pfnSaveState. */
365
#define SVC_MSG_QUIT (8) /* Terminate the thread. */
366
#define SVC_MSG_REGEXT (9) /* pfnRegisterExtension */
367
#define SVC_MSG_UNREGEXT (10) /* pfnRegisterExtension */
368
#ifdef VBOX_WITH_CRHGSMI
369
# define SVC_MSG_HOSTFASTCALLASYNC (21) /* pfnHostCall */
372
class HGCMMsgSvcLoad: public HGCMMsgCore
376
class HGCMMsgSvcUnload: public HGCMMsgCore
380
class HGCMMsgSvcConnect: public HGCMMsgCore
383
/* client identifier */
384
uint32_t u32ClientId;
387
class HGCMMsgSvcDisconnect: public HGCMMsgCore
390
/* client identifier */
391
uint32_t u32ClientId;
394
class HGCMMsgHeader: public HGCMMsgCore
397
HGCMMsgHeader () : pCmd (NULL), pHGCMPort (NULL) {};
399
/* Command pointer/identifier. */
402
/* Port to be informed on message completion. */
403
PPDMIHGCMPORT pHGCMPort;
407
class HGCMMsgCall: public HGCMMsgHeader
410
/* client identifier */
411
uint32_t u32ClientId;
413
/* function number */
414
uint32_t u32Function;
416
/* number of parameters */
419
VBOXHGCMSVCPARM *paParms;
422
class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
425
uint32_t u32ClientId;
429
class HGCMMsgHostCallSvc: public HGCMMsgCore
432
/* function number */
433
uint32_t u32Function;
435
/* number of parameters */
438
VBOXHGCMSVCPARM *paParms;
441
class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
444
/* Handle of the extension to be registered. */
445
HGCMSVCEXTHANDLE handle;
446
/* The extension entry point. */
447
PFNHGCMSVCEXT pfnExtension;
448
/* The extension pointer. */
452
class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
455
/* Handle of the registered extension. */
456
HGCMSVCEXTHANDLE handle;
459
#ifdef VBOX_WITH_CRHGSMI
460
class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
463
/* function number */
464
uint32_t u32Function;
466
VBOXHGCMSVCPARM Param;
467
/* completion info */
468
PHGCMHOSTFASTCALLCB pfnCompletion;
473
static HGCMMsgCore *hgcmMessageAllocSvc (uint32_t u32MsgId)
477
#ifdef VBOX_WITH_CRHGSMI
478
case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc ();
480
case SVC_MSG_LOAD: return new HGCMMsgSvcLoad ();
481
case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload ();
482
case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect ();
483
case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect ();
484
case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc ();
485
case SVC_MSG_GUESTCALL: return new HGCMMsgCall ();
486
case SVC_MSG_LOADSTATE:
487
case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient ();
488
case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension ();
489
case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension ();
491
AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
498
* The service thread. Loads the service library and calls the service entry points.
500
DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
502
HGCMService *pSvc = (HGCMService *)pvUser;
503
AssertRelease(pSvc != NULL);
509
HGCMMsgCore *pMsgCore;
510
int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
514
/* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
515
AssertMsgFailed (("%Rrc\n", rc));
519
/* Cache required information to avoid unnecessary pMsgCore access. */
520
uint32_t u32MsgId = pMsgCore->MsgId ();
524
#ifdef VBOX_WITH_CRHGSMI
525
case SVC_MSG_HOSTFASTCALLASYNC:
527
HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
529
LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
531
rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, 1, &pMsg->Param);
536
LogFlowFunc(("SVC_MSG_LOAD\n"));
537
rc = pSvc->loadServiceDLL ();
542
LogFlowFunc(("SVC_MSG_UNLOAD\n"));
543
if (pSvc->m_fntable.pfnUnload)
545
pSvc->m_fntable.pfnUnload (pSvc->m_fntable.pvService);
548
pSvc->unloadServiceDLL ();
552
case SVC_MSG_CONNECT:
554
HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
556
LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
558
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
562
rc = pSvc->m_fntable.pfnConnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
564
hgcmObjDereference (pClient);
568
rc = VERR_HGCM_INVALID_CLIENT_ID;
572
case SVC_MSG_DISCONNECT:
574
HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
576
LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
578
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
582
rc = pSvc->m_fntable.pfnDisconnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
584
hgcmObjDereference (pClient);
588
rc = VERR_HGCM_INVALID_CLIENT_ID;
592
case SVC_MSG_GUESTCALL:
594
HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
596
LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
597
pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
599
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
603
pSvc->m_fntable.pfnCall (pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
605
hgcmObjDereference (pClient);
609
rc = VERR_HGCM_INVALID_CLIENT_ID;
613
case SVC_MSG_HOSTCALL:
615
HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
617
LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n", pMsg->u32Function, pMsg->cParms, pMsg->paParms));
619
rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
622
case SVC_MSG_LOADSTATE:
624
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
626
LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
628
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
632
if (pSvc->m_fntable.pfnLoadState)
634
rc = pSvc->m_fntable.pfnLoadState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
637
hgcmObjDereference (pClient);
641
rc = VERR_HGCM_INVALID_CLIENT_ID;
645
case SVC_MSG_SAVESTATE:
647
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
649
LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
651
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
657
if (pSvc->m_fntable.pfnSaveState)
660
rc = pSvc->m_fntable.pfnSaveState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
661
g_fSaveState = false;
664
hgcmObjDereference (pClient);
668
rc = VERR_HGCM_INVALID_CLIENT_ID;
674
HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
676
LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
678
if (pSvc->m_hExtension)
680
rc = VERR_NOT_SUPPORTED;
684
if (pSvc->m_fntable.pfnRegisterExtension)
686
rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, pMsg->pfnExtension, pMsg->pvExtension);
690
rc = VERR_NOT_SUPPORTED;
695
pSvc->m_hExtension = pMsg->handle;
700
case SVC_MSG_UNREGEXT:
702
HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
704
LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
706
if (pSvc->m_hExtension != pMsg->handle)
708
rc = VERR_NOT_SUPPORTED;
712
if (pSvc->m_fntable.pfnRegisterExtension)
714
rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, NULL, NULL);
718
rc = VERR_NOT_SUPPORTED;
721
pSvc->m_hExtension = NULL;
727
AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
728
rc = VERR_NOT_SUPPORTED;
732
if (u32MsgId != SVC_MSG_GUESTCALL)
734
/* For SVC_MSG_GUESTCALL the service calls the completion helper.
735
* Other messages have to be completed here.
737
hgcmMsgComplete (pMsgCore, rc);
742
/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
744
HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
746
if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
748
/* Only call the completion for these messages. The helper
749
* is called by the service, and the service does not get
750
* any other messages.
752
hgcmMsgComplete (pMsgCore, rc);
760
/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId)
762
HGCMService *pService = static_cast <HGCMService *> (pvInstance);
766
pService->DisconnectClient (u32ClientId, true);
770
static DECLCALLBACK(void) hgcmMsgCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
772
/* Call the VMMDev port interface to issue IRQ notification. */
773
HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
775
LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
777
if (pMsgHdr->pHGCMPort && !g_fResetting)
779
pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
784
* The main HGCM methods of the service.
787
int HGCMService::instanceCreate (const char *pszServiceLibrary, const char *pszServiceName)
789
LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
791
/* The maximum length of the thread name, allowed by the RT is 15. */
792
char achThreadName[16];
794
strncpy (achThreadName, pszServiceName, 15);
795
achThreadName[15] = 0;
797
int rc = hgcmThreadCreate (&m_thread, achThreadName, hgcmServiceThread, this);
801
m_pszSvcName = RTStrDup (pszServiceName);
802
m_pszSvcLibrary = RTStrDup (pszServiceLibrary);
804
if (!m_pszSvcName || !m_pszSvcLibrary)
806
RTStrFree (m_pszSvcLibrary);
807
m_pszSvcLibrary = NULL;
809
RTStrFree (m_pszSvcName);
816
/* Initialize service helpers table. */
817
m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
818
m_svcHelpers.pvInstance = this;
819
m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
821
/* Execute the load request on the service thread. */
823
rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
827
rc = hgcmMsgSend (hMsg);
837
LogFlowFunc(("rc = %Rrc\n", rc));
841
void HGCMService::instanceDestroy (void)
843
LogFlowFunc(("%s\n", m_pszSvcName));
846
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
850
rc = hgcmMsgSend (hMsg);
854
hgcmThreadWait (m_thread);
858
RTStrFree (m_pszSvcLibrary);
859
m_pszSvcLibrary = NULL;
861
RTStrFree (m_pszSvcName);
865
int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
867
LogFlowFunc(("%s\n", m_pszSvcName));
870
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
874
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
877
pMsg->u32ClientId = u32ClientId;
880
hgcmObjDereference (pMsg);
882
rc = hgcmMsgSend (hMsg);
885
LogFlowFunc(("rc = %Rrc\n", rc));
889
int HGCMService::loadClientState (uint32_t u32ClientId, PSSMHANDLE pSSM)
891
LogFlowFunc(("%s\n", m_pszSvcName));
894
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
898
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
902
pMsg->u32ClientId = u32ClientId;
905
hgcmObjDereference (pMsg);
907
rc = hgcmMsgSend (hMsg);
910
LogFlowFunc(("rc = %Rrc\n", rc));
915
/** The method creates a service and references it.
917
* @param pszServiceLibrary The library to be loaded.
918
* @param pszServiceName The name of the service.
922
/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName)
924
LogFlowFunc(("lib %s, name = %s\n", pszServiceLibrary, pszServiceName));
926
/* Look at already loaded services to avoid double loading. */
929
int rc = HGCMService::ResolveService (&pSvc, pszServiceName);
933
/* The service is already loaded. */
934
pSvc->ReleaseService ();
935
rc = VERR_HGCM_SERVICE_EXISTS;
939
/* Create the new service. */
940
pSvc = new HGCMService ();
948
/* Load the library and call the initialization entry point. */
949
rc = pSvc->instanceCreate (pszServiceLibrary, pszServiceName);
953
/* Insert the just created service to list for future references. */
954
pSvc->m_pSvcNext = sm_pSvcListHead;
955
pSvc->m_pSvcPrev = NULL;
959
sm_pSvcListHead->m_pSvcPrev = pSvc;
963
sm_pSvcListTail = pSvc;
966
sm_pSvcListHead = pSvc;
970
/* Reference the service (for first time) until it is unloaded on HGCM termination. */
971
AssertRelease (pSvc->m_u32RefCnt == 0);
972
pSvc->ReferenceService ();
974
LogFlowFunc(("service %p\n", pSvc));
979
LogFlowFunc(("rc = %Rrc\n", rc));
983
/** The method unloads a service.
987
void HGCMService::UnloadService (void)
989
LogFlowFunc(("name = %s\n", m_pszSvcName));
991
/* Remove the service from the list. */
994
m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
998
sm_pSvcListTail = m_pSvcPrev;
1003
m_pSvcPrev->m_pSvcNext = m_pSvcNext;
1007
sm_pSvcListHead = m_pSvcNext;
1012
/* The service must be unloaded only if all clients were disconnected. */
1013
LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1014
AssertRelease (m_u32RefCnt == 1);
1016
/* Now the service can be released. */
1020
/** The method unloads all services.
1024
/* static */ void HGCMService::UnloadAll (void)
1026
while (sm_pSvcListHead)
1028
sm_pSvcListHead->UnloadService ();
1032
/** The method obtains a referenced pointer to the service with
1033
* specified name. The caller must call ReleaseService when
1034
* the pointer is no longer needed.
1036
* @param ppSvc Where to store the pointer to the service.
1037
* @param pszServiceName The name of the service.
1041
/* static */ int HGCMService::ResolveService (HGCMService **ppSvc, const char *pszServiceName)
1043
LogFlowFunc(("ppSvc = %p name = %s\n",
1044
ppSvc, pszServiceName));
1046
if (!ppSvc || !pszServiceName)
1048
return VERR_INVALID_PARAMETER;
1051
HGCMService *pSvc = sm_pSvcListHead;
1055
if (strcmp (pSvc->m_pszSvcName, pszServiceName) == 0)
1060
pSvc = pSvc->m_pSvcNext;
1063
LogFlowFunc(("lookup in the list is %p\n", pSvc));
1068
return VERR_HGCM_SERVICE_NOT_FOUND;
1071
pSvc->ReferenceService ();
1075
return VINF_SUCCESS;
1078
/** The method increases reference counter.
1082
void HGCMService::ReferenceService (void)
1084
ASMAtomicIncU32 (&m_u32RefCnt);
1085
LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1088
/** The method dereferences a service and deletes it when no more refs.
1092
void HGCMService::ReleaseService (void)
1094
LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1095
uint32_t u32RefCnt = ASMAtomicDecU32 (&m_u32RefCnt);
1096
AssertRelease(u32RefCnt != ~0U);
1098
LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1107
/** The method is called when the VM is being reset or terminated
1108
* and disconnects all clients from all services.
1112
/* static */ void HGCMService::Reset (void)
1114
g_fResetting = true;
1116
HGCMService *pSvc = sm_pSvcListHead;
1120
while (pSvc->m_cClients && pSvc->m_paClientIds)
1122
LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1123
pSvc->DisconnectClient (pSvc->m_paClientIds[0], false);
1126
#ifdef VBOX_WITH_CRHGSMI
1127
/* @todo: could this actually happen that the service is destroyed on ReleaseService? */
1128
HGCMService *pNextSvc = pSvc->m_pSvcNext;
1129
while (pSvc->m_cHandleAcquires)
1131
pSvc->HandleReleased ();
1132
pSvc->ReleaseService ();
1136
pSvc = pSvc->m_pSvcNext;
1140
g_fResetting = false;
1143
/** The method saves the HGCM state.
1145
* @param pSSM The saved state context.
1149
/* static */ int HGCMService::SaveState (PSSMHANDLE pSSM)
1151
/* Save the current handle count and restore afterwards to avoid client id conflicts. */
1152
int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1153
AssertRCReturn(rc, rc);
1155
LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1157
/* Save number of services. */
1158
rc = SSMR3PutU32(pSSM, sm_cServices);
1159
AssertRCReturn(rc, rc);
1161
/* Save every service. */
1162
HGCMService *pSvc = sm_pSvcListHead;
1166
LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1168
/* Save the length of the service name. */
1169
rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1170
AssertRCReturn(rc, rc);
1172
/* Save the name of the service. */
1173
rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1174
AssertRCReturn(rc, rc);
1176
/* Save the number of clients. */
1177
rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1178
AssertRCReturn(rc, rc);
1180
/* Call the service for every client. Normally a service must not have
1181
* a global state to be saved: only per client info is relevant.
1182
* The global state of a service is configured during VM startup.
1186
for (i = 0; i < pSvc->m_cClients; i++)
1188
uint32_t u32ClientId = pSvc->m_paClientIds[i];
1190
Log(("client id 0x%08X\n", u32ClientId));
1192
/* Save the client id. */
1193
rc = SSMR3PutU32(pSSM, u32ClientId);
1194
AssertRCReturn(rc, rc);
1196
/* Call the service, so the operation is executed by the service thread. */
1197
rc = pSvc->saveClientState (u32ClientId, pSSM);
1198
AssertRCReturn(rc, rc);
1201
pSvc = pSvc->m_pSvcNext;
1204
return VINF_SUCCESS;
1207
/** The method loads saved HGCM state.
1209
* @param pSSM The saved state context.
1213
/* static */ int HGCMService::LoadState (PSSMHANDLE pSSM)
1215
/* Restore handle count to avoid client id conflicts. */
1218
int rc = SSMR3GetU32(pSSM, &u32);
1219
AssertRCReturn(rc, rc);
1221
hgcmObjSetHandleCount(u32);
1223
/* Get the number of services. */
1226
rc = SSMR3GetU32(pSSM, &cServices);
1227
AssertRCReturn(rc, rc);
1229
LogFlowFunc(("%d services to be restored:\n", cServices));
1233
/* Get the length of the service name. */
1234
rc = SSMR3GetU32(pSSM, &u32);
1235
AssertRCReturn(rc, rc);
1236
AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1238
char *pszServiceName = (char *)alloca (u32);
1240
/* Get the service name. */
1241
rc = SSMR3GetStrZ(pSSM, pszServiceName, u32);
1242
AssertRCReturn(rc, rc);
1244
LogRel(("HGCM: restoring [%s]\n", pszServiceName));
1246
/* Resolve the service instance. */
1248
rc = ResolveService (&pSvc, pszServiceName);
1249
AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, pszServiceName), VERR_SSM_UNEXPECTED_DATA);
1251
/* Get the number of clients. */
1253
rc = SSMR3GetU32(pSSM, &cClients);
1256
pSvc->ReleaseService ();
1263
/* Get the client id. */
1264
uint32_t u32ClientId;
1265
rc = SSMR3GetU32(pSSM, &u32ClientId);
1268
pSvc->ReleaseService ();
1273
/* Connect the client. */
1274
rc = pSvc->CreateAndConnectClient (NULL, u32ClientId);
1277
pSvc->ReleaseService ();
1278
AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
1282
/* Call the service, so the operation is executed by the service thread. */
1283
rc = pSvc->loadClientState (u32ClientId, pSSM);
1286
pSvc->ReleaseService ();
1287
AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
1292
pSvc->ReleaseService ();
1295
return VINF_SUCCESS;
1298
/* Create a new client instance and connect it to the service.
1300
* @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1301
* If NULL, use the given 'u32ClientIdIn' handle.
1302
* @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1305
int HGCMService::CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
1307
LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
1309
/* Allocate a client information structure. */
1310
HGCMClient *pClient = new HGCMClient ();
1314
LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
1315
return VERR_NO_MEMORY;
1320
if (pu32ClientIdOut != NULL)
1322
handle = hgcmObjGenerateHandle (pClient);
1326
handle = hgcmObjAssignHandle (pClient, u32ClientIdIn);
1329
LogFlowFunc(("client id = %d\n", handle));
1331
AssertRelease(handle);
1333
/* Initialize the HGCM part of the client. */
1334
int rc = pClient->Init (this);
1338
/* Call the service. */
1341
rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1345
HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1346
AssertRelease(pMsg);
1348
pMsg->u32ClientId = handle;
1350
hgcmObjDereference (pMsg);
1352
rc = hgcmMsgSend (hMsg);
1356
/* Add the client Id to the array. */
1357
if (m_cClients == m_cClientsAllocated)
1359
m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
1360
Assert(m_paClientIds);
1361
m_cClientsAllocated += 64;
1364
m_paClientIds[m_cClients] = handle;
1372
hgcmObjDeleteHandle (handle);
1376
if (pu32ClientIdOut != NULL)
1378
*pu32ClientIdOut = handle;
1381
ReferenceService ();
1384
LogFlowFunc(("rc = %Rrc\n", rc));
1388
/* Disconnect the client from the service and delete the client handle.
1390
* @param u32ClientId The handle of the client.
1393
int HGCMService::DisconnectClient (uint32_t u32ClientId, bool fFromService)
1395
int rc = VINF_SUCCESS;
1397
LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1401
/* Call the service. */
1404
rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1408
HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1409
AssertRelease(pMsg);
1411
pMsg->u32ClientId = u32ClientId;
1413
hgcmObjDereference (pMsg);
1415
rc = hgcmMsgSend (hMsg);
1419
LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1420
u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_thread, rc));
1424
/* Remove the client id from the array in any case, rc does not matter. */
1427
for (i = 0; i < m_cClients; i++)
1429
if (m_paClientIds[i] == u32ClientId)
1435
memmove (&m_paClientIds[i], &m_paClientIds[i + 1], sizeof (m_paClientIds[0]) * (m_cClients - i));
1438
/* Delete the client handle. */
1439
hgcmObjDeleteHandle (u32ClientId);
1441
/* The service must be released. */
1448
LogFlowFunc(("rc = %Rrc\n", rc));
1452
int HGCMService::RegisterExtension (HGCMSVCEXTHANDLE handle,
1453
PFNHGCMSVCEXT pfnExtension,
1456
LogFlowFunc(("%s\n", handle->pszServiceName));
1458
/* Forward the message to the service thread. */
1459
HGCMMSGHANDLE hMsg = 0;
1460
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1464
HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1465
AssertRelease(pMsg);
1467
pMsg->handle = handle;
1468
pMsg->pfnExtension = pfnExtension;
1469
pMsg->pvExtension = pvExtension;
1471
hgcmObjDereference (pMsg);
1473
rc = hgcmMsgSend (hMsg);
1476
LogFlowFunc(("rc = %Rrc\n", rc));
1480
void HGCMService::UnregisterExtension (HGCMSVCEXTHANDLE handle)
1482
/* Forward the message to the service thread. */
1483
HGCMMSGHANDLE hMsg = 0;
1484
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1488
HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1489
AssertRelease(pMsg);
1491
pMsg->handle = handle;
1493
hgcmObjDereference (pMsg);
1495
rc = hgcmMsgSend (hMsg);
1498
LogFlowFunc(("rc = %Rrc\n", rc));
1501
/* Perform a guest call to the service.
1503
* @param pHGCMPort The port to be used for completion confirmation.
1504
* @param pCmd The VBox HGCM context.
1505
* @param u32ClientId The client handle to be disconnected and deleted.
1506
* @param u32Function The function number.
1507
* @param cParms Number of parameters.
1508
* @param paParms Pointer to array of parameters.
1511
int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1513
HGCMMSGHANDLE hMsg = 0;
1515
LogFlow(("MAIN::HGCMService::Call\n"));
1517
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_GUESTCALL, hgcmMessageAllocSvc);
1521
HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1523
AssertRelease(pMsg);
1526
pMsg->pHGCMPort = pHGCMPort;
1528
pMsg->u32ClientId = u32ClientId;
1529
pMsg->u32Function = u32Function;
1530
pMsg->cParms = cParms;
1531
pMsg->paParms = paParms;
1533
hgcmObjDereference (pMsg);
1535
rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1539
Log(("MAIN::HGCMService::Call: Message allocation failed: %Rrc\n", rc));
1542
LogFlowFunc(("rc = %Rrc\n", rc));
1546
/* Perform a host call the service.
1548
* @param u32Function The function number.
1549
* @param cParms Number of parameters.
1550
* @param paParms Pointer to array of parameters.
1553
int HGCMService::HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1555
LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1556
m_pszSvcName, u32Function, cParms, paParms));
1558
HGCMMSGHANDLE hMsg = 0;
1559
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1563
HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1564
AssertRelease(pMsg);
1566
pMsg->u32Function = u32Function;
1567
pMsg->cParms = cParms;
1568
pMsg->paParms = paParms;
1570
hgcmObjDereference (pMsg);
1572
rc = hgcmMsgSend (hMsg);
1575
LogFlowFunc(("rc = %Rrc\n", rc));
1579
#ifdef VBOX_WITH_CRHGSMI
1580
static DECLCALLBACK(void) hgcmMsgFastCallCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
1582
/* Call the VMMDev port interface to issue IRQ notification. */
1583
LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
1585
HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
1586
if (pMsg->pfnCompletion)
1588
pMsg->pfnCompletion (result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
1592
int HGCMService::HandleAcquired()
1594
++m_cHandleAcquires;
1595
return VINF_SUCCESS;
1598
int HGCMService::HandleReleased()
1600
Assert(m_cHandleAcquires);
1601
if (m_cHandleAcquires)
1603
--m_cHandleAcquires;
1604
return VINF_SUCCESS;
1606
return VERR_INVALID_STATE;
1609
int HGCMService::HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
1611
LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
1612
m_pszSvcName, u32Function, pParm));
1614
HGCMMSGHANDLE hMsg = 0;
1615
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
1619
HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1620
AssertRelease(pMsg);
1622
pMsg->u32Function = u32Function;
1623
pMsg->Param = *pParm;
1624
pMsg->pfnCompletion = pfnCompletion;
1625
pMsg->pvCompletion = pvCompletion;
1627
hgcmObjDereference (pMsg);
1629
rc = hgcmMsgPost(hMsg, hgcmMsgFastCallCompletionCallback);
1632
LogFlowFunc(("rc = %Rrc\n", rc));
1638
* Main HGCM thread that manages services.
1641
/* Messages processed by the main HGCM thread. */
1642
#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1643
#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1644
#define HGCM_MSG_LOAD (12) /* Load the service. */
1645
#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1646
#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1647
#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1648
#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1649
#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1650
#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1651
#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1652
#ifdef VBOX_WITH_CRHGSMI
1653
# define HGCM_MSG_SVCAQUIRE (30) /* Acquire a service handle (for fast host calls) */
1654
# define HGCM_MSG_SVCRELEASE (31) /* Release a service */
1657
class HGCMMsgMainConnect: public HGCMMsgHeader
1661
const char *pszServiceName;
1662
/* Where to store the client handle. */
1663
uint32_t *pu32ClientId;
1666
class HGCMMsgMainDisconnect: public HGCMMsgHeader
1669
/* Handle of the client to be disconnected. */
1670
uint32_t u32ClientId;
1673
class HGCMMsgMainLoad: public HGCMMsgCore
1676
/* Name of the library to be loaded. */
1677
const char *pszServiceLibrary;
1678
/* Name to be assigned to the service. */
1679
const char *pszServiceName;
1682
class HGCMMsgMainHostCall: public HGCMMsgCore
1685
/* Which service to call. */
1686
const char *pszServiceName;
1687
/* Function number. */
1688
uint32_t u32Function;
1689
/* Number of the function parameters. */
1691
/* Pointer to array of the function parameters. */
1692
VBOXHGCMSVCPARM *paParms;
1695
class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1702
class HGCMMsgMainReset: public HGCMMsgCore
1706
class HGCMMsgMainQuit: public HGCMMsgCore
1710
class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1713
/* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1714
HGCMSVCEXTHANDLE *pHandle;
1715
/* Name of the service. */
1716
const char *pszServiceName;
1717
/* The extension entry point. */
1718
PFNHGCMSVCEXT pfnExtension;
1719
/* The extension pointer. */
1723
class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1726
/* Handle of the registered extension. */
1727
HGCMSVCEXTHANDLE handle;
1730
#ifdef VBOX_WITH_CRHGSMI
1731
class HGCMMsgMainSvcAcquire: public HGCMMsgCore
1734
/* Which service to call. */
1735
const char *pszServiceName;
1736
/* Returned service. */
1737
HGCMService *pService;
1740
class HGCMMsgMainSvcRelease: public HGCMMsgCore
1744
HGCMService *pService;
1749
static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1753
case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect ();
1754
case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
1755
case HGCM_MSG_LOAD: return new HGCMMsgMainLoad ();
1756
case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall ();
1757
case HGCM_MSG_LOADSTATE:
1758
case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState ();
1759
case HGCM_MSG_RESET: return new HGCMMsgMainReset ();
1760
case HGCM_MSG_QUIT: return new HGCMMsgMainQuit ();
1761
case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension ();
1762
case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension ();
1763
#ifdef VBOX_WITH_CRHGSMI
1764
case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
1765
case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
1769
AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1776
/* The main HGCM thread handler. */
1777
static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
1779
LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
1780
ThreadHandle, pvUser));
1788
HGCMMsgCore *pMsgCore;
1789
int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
1793
/* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
1794
AssertMsgFailed (("%Rrc\n", rc));
1798
uint32_t u32MsgId = pMsgCore->MsgId ();
1802
case HGCM_MSG_CONNECT:
1804
HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
1806
LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
1807
pMsg->pszServiceName, pMsg->pu32ClientId));
1809
/* Resolve the service name to the pointer to service instance.
1811
HGCMService *pService;
1812
rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1816
/* Call the service instance method. */
1817
rc = pService->CreateAndConnectClient (pMsg->pu32ClientId, 0);
1819
/* Release the service after resolve. */
1820
pService->ReleaseService ();
1824
case HGCM_MSG_DISCONNECT:
1826
HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
1828
LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
1829
pMsg->u32ClientId));
1831
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
1835
rc = VERR_HGCM_INVALID_CLIENT_ID;
1839
/* The service the client belongs to. */
1840
HGCMService *pService = pClient->pService;
1842
/* Call the service instance to disconnect the client. */
1843
rc = pService->DisconnectClient (pMsg->u32ClientId, false);
1845
hgcmObjDereference (pClient);
1850
HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
1852
LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
1853
pMsg->pszServiceName, pMsg->pszServiceLibrary));
1855
rc = HGCMService::LoadService (pMsg->pszServiceLibrary, pMsg->pszServiceName);
1858
case HGCM_MSG_HOSTCALL:
1860
HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
1862
LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
1863
pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
1865
/* Resolve the service name to the pointer to service instance. */
1866
HGCMService *pService;
1867
rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1871
rc = pService->HostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
1873
pService->ReleaseService ();
1877
#ifdef VBOX_WITH_CRHGSMI
1878
case HGCM_MSG_SVCAQUIRE:
1880
HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
1882
LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
1884
/* Resolve the service name to the pointer to service instance. */
1885
HGCMService *pService;
1886
rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1889
rc = pService->HandleAcquired ();
1892
pMsg->pService = pService;
1896
pService->ReleaseService ();
1901
case HGCM_MSG_SVCRELEASE:
1903
HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
1905
LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
1907
/* Resolve the service name to the pointer to service instance. */
1909
rc = pMsg->pService->HandleReleased ();
1912
pMsg->pService->ReleaseService ();
1917
case HGCM_MSG_RESET:
1919
LogFlowFunc(("HGCM_MSG_RESET\n"));
1921
HGCMService::Reset ();
1924
case HGCM_MSG_LOADSTATE:
1926
HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1928
LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
1930
rc = HGCMService::LoadState (pMsg->pSSM);
1933
case HGCM_MSG_SAVESTATE:
1935
HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1937
LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
1939
rc = HGCMService::SaveState (pMsg->pSSM);
1944
LogFlowFunc(("HGCM_MSG_QUIT\n"));
1946
HGCMService::UnloadAll ();
1951
case HGCM_MSG_REGEXT:
1953
HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
1955
LogFlowFunc(("HGCM_MSG_REGEXT\n"));
1957
/* Allocate the handle data. */
1958
HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ (sizeof (struct _HGCMSVCEXTHANDLEDATA)
1959
+ strlen (pMsg->pszServiceName)
1964
rc = VERR_NO_MEMORY;
1968
handle->pszServiceName = (char *)((uint8_t *)handle + sizeof (struct _HGCMSVCEXTHANDLEDATA));
1969
strcpy (handle->pszServiceName, pMsg->pszServiceName);
1971
HGCMService *pService;
1972
rc = HGCMService::ResolveService (&pService, handle->pszServiceName);
1976
pService->RegisterExtension (handle, pMsg->pfnExtension, pMsg->pvExtension);
1978
pService->ReleaseService ();
1987
*pMsg->pHandle = handle;
1992
case HGCM_MSG_UNREGEXT:
1994
HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
1996
LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
1998
HGCMService *pService;
1999
rc = HGCMService::ResolveService (&pService, pMsg->handle->pszServiceName);
2003
pService->UnregisterExtension (pMsg->handle);
2005
pService->ReleaseService ();
2008
RTMemFree (pMsg->handle);
2013
AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
2014
rc = VERR_NOT_SUPPORTED;
2018
/* Complete the message processing. */
2019
hgcmMsgComplete (pMsgCore, rc);
2021
LogFlowFunc(("message processed %Rrc\n", rc));
2030
/* The main hgcm thread. */
2031
static HGCMTHREADHANDLE g_hgcmThread = 0;
2034
* Public HGCM functions.
2036
* hgcmGuest* - called as a result of the guest HGCM requests.
2037
* hgcmHost* - called by the host.
2040
/* Load a HGCM service from the specified library.
2041
* Assign the specified name to the service.
2043
* @param pszServiceLibrary The library to be loaded.
2044
* @param pszServiceName The name to be assigned to the service.
2047
int HGCMHostLoad (const char *pszServiceLibrary,
2048
const char *pszServiceName)
2050
LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
2052
if (!pszServiceLibrary || !pszServiceName)
2054
return VERR_INVALID_PARAMETER;
2057
/* Forward the request to the main hgcm thread. */
2058
HGCMMSGHANDLE hMsg = 0;
2060
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
2064
/* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2065
HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2066
AssertRelease(pMsg);
2068
pMsg->pszServiceLibrary = pszServiceLibrary;
2069
pMsg->pszServiceName = pszServiceName;
2071
hgcmObjDereference (pMsg);
2073
rc = hgcmMsgSend (hMsg);
2076
LogFlowFunc(("rc = %Rrc\n", rc));
2080
/* Register a HGCM service extension.
2082
* @param pHandle Returned handle for the registered extension.
2083
* @param pszServiceName The name of the service.
2084
* @param pfnExtension The extension entry point (callback).
2085
* @param pvExtension The extension pointer.
2088
int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle,
2089
const char *pszServiceName,
2090
PFNHGCMSVCEXT pfnExtension,
2093
LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
2095
if (!pHandle || !pszServiceName || !pfnExtension)
2097
return VERR_INVALID_PARAMETER;
2100
/* Forward the request to the main hgcm thread. */
2101
HGCMMSGHANDLE hMsg = 0;
2103
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
2107
/* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2108
HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2109
AssertRelease(pMsg);
2111
pMsg->pHandle = pHandle;
2112
pMsg->pszServiceName = pszServiceName;
2113
pMsg->pfnExtension = pfnExtension;
2114
pMsg->pvExtension = pvExtension;
2116
hgcmObjDereference (pMsg);
2118
rc = hgcmMsgSend (hMsg);
2121
LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
2125
void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle)
2127
LogFlowFunc(("handle = %p\n", handle));
2129
/* Forward the request to the main hgcm thread. */
2130
HGCMMSGHANDLE hMsg = 0;
2132
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
2136
/* Initialize the message. */
2137
HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2138
AssertRelease(pMsg);
2140
pMsg->handle = handle;
2142
hgcmObjDereference (pMsg);
2144
rc = hgcmMsgSend (hMsg);
2147
LogFlowFunc(("rc = %Rrc\n", rc));
2151
/* Find a service and inform it about a client connection, create a client handle.
2153
* @param pHGCMPort The port to be used for completion confirmation.
2154
* @param pCmd The VBox HGCM context.
2155
* @param pszServiceName The name of the service to be connected to.
2156
* @param pu32ClientId Where the store the created client handle.
2159
int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort,
2161
const char *pszServiceName,
2162
uint32_t *pu32ClientId)
2164
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
2165
pHGCMPort, pCmd, pszServiceName, pu32ClientId));
2167
if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
2169
return VERR_INVALID_PARAMETER;
2172
/* Forward the request to the main hgcm thread. */
2173
HGCMMSGHANDLE hMsg = 0;
2175
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
2179
/* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
2180
* will not be deallocated by the caller until the message is completed,
2181
* use the supplied pointers.
2183
HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2184
AssertRelease(pMsg);
2186
pMsg->pHGCMPort = pHGCMPort;
2188
pMsg->pszServiceName = pszServiceName;
2189
pMsg->pu32ClientId = pu32ClientId;
2191
hgcmObjDereference (pMsg);
2193
rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2196
LogFlowFunc(("rc = %Rrc\n", rc));
2200
/* Tell a service that the client is disconnecting, destroy the client handle.
2202
* @param pHGCMPort The port to be used for completion confirmation.
2203
* @param pCmd The VBox HGCM context.
2204
* @param u32ClientId The client handle to be disconnected and deleted.
2207
int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort,
2209
uint32_t u32ClientId)
2211
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2212
pHGCMPort, pCmd, u32ClientId));
2214
if (!pHGCMPort || !pCmd || !u32ClientId)
2216
return VERR_INVALID_PARAMETER;
2219
/* Forward the request to the main hgcm thread. */
2220
HGCMMSGHANDLE hMsg = 0;
2222
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2226
/* Initialize the message. */
2227
HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2228
AssertRelease(pMsg);
2231
pMsg->pHGCMPort = pHGCMPort;
2232
pMsg->u32ClientId = u32ClientId;
2234
hgcmObjDereference (pMsg);
2236
rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2239
LogFlowFunc(("rc = %Rrc\n", rc));
2243
/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2245
* @param pSSM The SSM handle.
2246
* @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2249
static int hgcmHostLoadSaveState (PSSMHANDLE pSSM,
2252
LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
2254
HGCMMSGHANDLE hMsg = 0;
2256
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, u32MsgId, hgcmMainMessageAlloc);
2260
HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2261
AssertRelease(pMsg);
2265
hgcmObjDereference (pMsg);
2267
rc = hgcmMsgSend (hMsg);
2270
LogFlowFunc(("rc = %Rrc\n", rc));
2274
/* Save the state of services.
2276
* @param pSSM The SSM handle.
2279
int HGCMHostSaveState (PSSMHANDLE pSSM)
2281
return hgcmHostLoadSaveState (pSSM, HGCM_MSG_SAVESTATE);
2284
/* Load the state of services.
2286
* @param pSSM The SSM handle.
2289
int HGCMHostLoadState (PSSMHANDLE pSSM)
2291
return hgcmHostLoadSaveState (pSSM, HGCM_MSG_LOADSTATE);
2294
/* The guest calls the service.
2296
* @param pHGCMPort The port to be used for completion confirmation.
2297
* @param pCmd The VBox HGCM context.
2298
* @param u32ClientId The client handle to be disconnected and deleted.
2299
* @param u32Function The function number.
2300
* @param cParms Number of parameters.
2301
* @param paParms Pointer to array of parameters.
2304
int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort,
2306
uint32_t u32ClientId,
2307
uint32_t u32Function,
2309
VBOXHGCMSVCPARM *paParms)
2311
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2312
pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2314
if (!pHGCMPort || !pCmd || u32ClientId == 0)
2316
return VERR_INVALID_PARAMETER;
2319
int rc = VERR_HGCM_INVALID_CLIENT_ID;
2321
/* Resolve the client handle to the client instance pointer. */
2322
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientId, HGCMOBJ_CLIENT);
2326
AssertRelease(pClient->pService);
2328
/* Forward the message to the service thread. */
2329
rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
2331
hgcmObjDereference (pClient);
2334
LogFlowFunc(("rc = %Rrc\n", rc));
2338
/* The host calls the service.
2340
* @param pszServiceName The service name to be called.
2341
* @param u32Function The function number.
2342
* @param cParms Number of parameters.
2343
* @param paParms Pointer to array of parameters.
2346
int HGCMHostCall (const char *pszServiceName,
2347
uint32_t u32Function,
2349
VBOXHGCMSVCPARM *paParms)
2351
LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2352
pszServiceName, u32Function, cParms, paParms));
2354
if (!pszServiceName)
2356
return VERR_INVALID_PARAMETER;
2359
HGCMMSGHANDLE hMsg = 0;
2361
/* Host calls go to main HGCM thread that resolves the service name to the
2362
* service instance pointer and then, using the service pointer, forwards
2363
* the message to the service thread.
2364
* So it is slow but host calls are intended mostly for configuration and
2365
* other non-time-critical functions.
2367
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2371
HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2372
AssertRelease(pMsg);
2374
pMsg->pszServiceName = (char *)pszServiceName;
2375
pMsg->u32Function = u32Function;
2376
pMsg->cParms = cParms;
2377
pMsg->paParms = paParms;
2379
hgcmObjDereference (pMsg);
2381
rc = hgcmMsgSend (hMsg);
2384
LogFlowFunc(("rc = %Rrc\n", rc));
2388
#ifdef VBOX_WITH_CRHGSMI
2389
int HGCMHostSvcHandleCreate (const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2391
LogFlowFunc(("name = %s\n", pszServiceName));
2393
if (!pszServiceName)
2395
return VERR_INVALID_PARAMETER;
2400
return VERR_INVALID_PARAMETER;
2403
HGCMMSGHANDLE hMsg = 0;
2405
/* Host calls go to main HGCM thread that resolves the service name to the
2406
* service instance pointer and then, using the service pointer, forwards
2407
* the message to the service thread.
2408
* So it is slow but host calls are intended mostly for configuration and
2409
* other non-time-critical functions.
2411
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2415
HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2416
AssertRelease(pMsg);
2418
pMsg->pszServiceName = (char *)pszServiceName;
2419
pMsg->pService = NULL;
2421
rc = hgcmMsgSend (hMsg);
2424
/* for simplicity just use a svc ptr as handle for now */
2425
*phSvc = (HGCMCVSHANDLE)pMsg->pService;
2428
hgcmObjDereference (pMsg);
2431
LogFlowFunc(("rc = %Rrc\n", rc));
2435
int HGCMHostSvcHandleDestroy (HGCMCVSHANDLE hSvc)
2437
LogFlowFunc(("hSvc = %p\n", hSvc));
2441
return VERR_INVALID_PARAMETER;
2444
HGCMMSGHANDLE hMsg = 0;
2446
/* Host calls go to main HGCM thread that resolves the service name to the
2447
* service instance pointer and then, using the service pointer, forwards
2448
* the message to the service thread.
2449
* So it is slow but host calls are intended mostly for configuration and
2450
* other non-time-critical functions.
2452
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2456
HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2457
AssertRelease(pMsg);
2459
pMsg->pService = (HGCMService *)hSvc;
2461
hgcmObjDereference (pMsg);
2463
rc = hgcmMsgSend (hMsg);
2466
LogFlowFunc(("rc = %Rrc\n", rc));
2470
int HGCMHostFastCallAsync (HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
2472
LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2473
hSvc, function, pParm));
2477
return VERR_INVALID_PARAMETER;
2480
HGCMService *pService = (HGCMService *)hSvc;
2481
int rc = pService->HostFastCallAsync (function, pParm, pfnCompletion, pvCompletion);
2483
LogFlowFunc(("rc = %Rrc\n", rc));
2488
int HGCMHostReset (void)
2490
LogFlowFunc(("\n"));
2492
/* Disconnect all clients.
2495
HGCMMSGHANDLE hMsg = 0;
2497
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2501
rc = hgcmMsgSend (hMsg);
2504
LogFlowFunc(("rc = %Rrc\n", rc));
2508
int HGCMHostInit (void)
2510
LogFlowFunc(("\n"));
2512
int rc = hgcmThreadInit ();
2517
* Start main HGCM thread.
2520
rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
2524
LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2528
LogFlowFunc(("rc = %Rrc\n", rc));
2532
int HGCMHostShutdown (void)
2534
LogFlowFunc(("\n"));
2537
* Do HGCMReset and then unload all services.
2540
int rc = HGCMHostReset ();
2544
/* Send the quit message to the main hgcmThread. */
2545
HGCMMSGHANDLE hMsg = 0;
2547
rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2551
rc = hgcmMsgSend (hMsg);
2555
/* Wait for the thread termination. */
2556
hgcmThreadWait (g_hgcmThread);
2559
hgcmThreadUninit ();
2564
LogFlowFunc(("rc = %Rrc\n", rc));